summaryrefslogtreecommitdiff
path: root/Source/ThirdParty
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
commit40736c5763bf61337c8c14e16d8587db021a87d4 (patch)
treeb17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/ThirdParty
downloadqtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/ThirdParty')
-rw-r--r--Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj662
-rw-r--r--Source/ThirdParty/ANGLE/ChangeLog1914
-rw-r--r--Source/ThirdParty/ANGLE/Configurations/ANGLE.xcconfig5
-rw-r--r--Source/ThirdParty/ANGLE/Configurations/Base.xcconfig47
-rw-r--r--Source/ThirdParty/ANGLE/Configurations/CompilerVersion.xcconfig84
-rw-r--r--Source/ThirdParty/ANGLE/Configurations/DebugRelease.xcconfig19
-rw-r--r--Source/ThirdParty/ANGLE/Makefile1
-rw-r--r--Source/ThirdParty/ANGLE/include/EGL/egl.h329
-rw-r--r--Source/ThirdParty/ANGLE/include/EGL/eglext.h235
-rw-r--r--Source/ThirdParty/ANGLE/include/EGL/eglplatform.h110
-rw-r--r--Source/ThirdParty/ANGLE/include/GLES2/gl2.h621
-rw-r--r--Source/ThirdParty/ANGLE/include/GLES2/gl2ext.h831
-rw-r--r--Source/ThirdParty/ANGLE/include/GLES2/gl2platform.h30
-rw-r--r--Source/ThirdParty/ANGLE/include/GLSLANG/ShaderLang.h284
-rw-r--r--Source/ThirdParty/ANGLE/include/KHR/khrplatform.h269
-rw-r--r--Source/ThirdParty/ANGLE/src/build_angle.xcodeproj/project.pbxproj687
-rw-r--r--Source/ThirdParty/ANGLE/src/common/angleutils.h18
-rw-r--r--Source/ThirdParty/ANGLE/src/common/debug.cpp97
-rw-r--r--Source/ThirdParty/ANGLE/src/common/debug.h103
-rw-r--r--Source/ThirdParty/ANGLE/src/common/version.h10
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/BaseTypes.h147
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/CodeGenGLSL.cpp34
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/CodeGenHLSL.cpp31
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Common.h89
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Compiler.cpp224
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ConstantUnion.h258
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ExtensionBehavior.h37
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.cpp172
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.h46
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InfoSink.cpp59
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InfoSink.h115
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Initialize.cpp629
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Initialize.h35
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InitializeDll.cpp115
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InitializeDll.h16
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InitializeGlobals.h15
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.h16
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/IntermTraverse.cpp293
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Intermediate.cpp1454
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/MMap.h56
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.cpp98
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.h39
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputESSL.cpp22
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputESSL.h21
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.cpp17
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.h21
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.cpp707
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.h53
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.cpp2349
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.h131
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ParseHelper.cpp1533
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ParseHelper.h119
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.cpp304
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.h300
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.cpp58
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.h7
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/RemoveTree.cpp77
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/RemoveTree.h7
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.cpp38
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.h33
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ShHandle.h113
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ShaderLang.cpp262
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/SymbolTable.cpp232
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/SymbolTable.h348
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.cpp34
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.h23
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.cpp37
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.h20
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.cpp22
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.h20
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/Types.h293
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/UnfoldSelect.cpp65
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/UnfoldSelect.h37
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.cpp543
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.h63
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VariableInfo.cpp220
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VariableInfo.h43
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.cpp115
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.h52
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/debug.cpp36
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/debug.h53
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/generate_glslang_lexer.sh11
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/generate_glslang_parser.sh12
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/glslang.h16
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/glslang.l570
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/glslang.y2072
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/glslang_lex.cpp3190
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/glslang_tab.cpp4716
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/glslang_tab.h274
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/intermOut.cpp417
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/intermediate.h544
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/localintermediate.h58
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/osinclude.h70
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ossource_nspr.cpp43
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ossource_posix.cpp60
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/ossource_win.cpp57
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/parseConst.cpp238
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/atom.c736
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/atom.h63
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/compile.h100
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/cpp.c1114
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/cpp.h86
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/cppstruct.c152
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/memory.c154
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/memory.h56
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/parser.h93
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/preprocess.h51
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/scanner.c688
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/scanner.h84
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/slglobals.h82
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/symbols.c284
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/symbols.h112
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/tokens.c436
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/preprocessor/tokens.h89
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/util.cpp33
-rw-r--r--Source/ThirdParty/ANGLE/src/compiler/util.h21
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/Config.cpp399
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/Config.h118
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/Display.cpp897
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/Display.h118
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp495
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/Surface.h105
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp1170
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/libEGL.def36
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/libEGL.rc102
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/libEGL.vcproj266
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/main.cpp161
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/main.h61
-rw-r--r--Source/ThirdParty/ANGLE/src/libEGL/resource.h14
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Blit.cpp599
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Blit.h94
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.cpp115
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.h61
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp3766
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Context.h581
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Fence.cpp134
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Fence.h43
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.cpp454
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.h95
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.cpp63
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.h45
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.cpp404
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.h120
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Program.cpp3021
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Program.h226
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/RefCountObject.cpp52
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/RefCountObject.h70
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.cpp512
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.h192
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.cpp320
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.h104
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Shader.cpp528
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Shader.h157
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp2589
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Texture.h312
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.cpp733
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.h168
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp382
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.h120
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/geometry/VertexDataManager.cpp769
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/geometry/VertexDataManager.h170
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/geometry/vertexconversion.h208
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.cpp5723
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.def164
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.rc102
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.vcproj369
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/main.cpp143
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/main.h47
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/mathutil.h119
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/resource.h14
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/utilities.cpp882
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/utilities.h87
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/vertexconversion.h208
-rw-r--r--Source/ThirdParty/ChangeLog236
-rw-r--r--Source/ThirdParty/Makefile17
-rw-r--r--Source/ThirdParty/Makefile.shared2
-rw-r--r--Source/ThirdParty/glu/LICENSE.txt31
-rw-r--r--Source/ThirdParty/glu/README.webkit38
-rw-r--r--Source/ThirdParty/glu/glu.gyp36
-rw-r--r--Source/ThirdParty/glu/gluos.h60
-rw-r--r--Source/ThirdParty/glu/internal_glu.h141
-rw-r--r--Source/ThirdParty/glu/libtess/GNUmakefile110
-rw-r--r--Source/ThirdParty/glu/libtess/Imakefile61
-rw-r--r--Source/ThirdParty/glu/libtess/README447
-rw-r--r--Source/ThirdParty/glu/libtess/alg-outline229
-rw-r--r--Source/ThirdParty/glu/libtess/dict-list.h107
-rw-r--r--Source/ThirdParty/glu/libtess/dict.c117
-rw-r--r--Source/ThirdParty/glu/libtess/dict.h107
-rw-r--r--Source/ThirdParty/glu/libtess/geom.c271
-rw-r--r--Source/ThirdParty/glu/libtess/geom.h90
-rw-r--r--Source/ThirdParty/glu/libtess/memalloc.c62
-rw-r--r--Source/ThirdParty/glu/libtess/memalloc.h61
-rw-r--r--Source/ThirdParty/glu/libtess/mesh.c796
-rw-r--r--Source/ThirdParty/glu/libtess/mesh.h273
-rw-r--r--Source/ThirdParty/glu/libtess/normal.c259
-rw-r--r--Source/ThirdParty/glu/libtess/normal.h52
-rw-r--r--Source/ThirdParty/glu/libtess/priorityq-heap.c260
-rw-r--r--Source/ThirdParty/glu/libtess/priorityq-heap.h114
-rw-r--r--Source/ThirdParty/glu/libtess/priorityq-sort.h124
-rw-r--r--Source/ThirdParty/glu/libtess/priorityq.c267
-rw-r--r--Source/ThirdParty/glu/libtess/priorityq.h124
-rw-r--r--Source/ThirdParty/glu/libtess/render.c505
-rw-r--r--Source/ThirdParty/glu/libtess/render.h59
-rw-r--r--Source/ThirdParty/glu/libtess/sweep.c1362
-rw-r--r--Source/ThirdParty/glu/libtess/sweep.h84
-rw-r--r--Source/ThirdParty/glu/libtess/tess.c638
-rw-r--r--Source/ThirdParty/glu/libtess/tess.h172
-rw-r--r--Source/ThirdParty/glu/libtess/tessmono.c208
-rw-r--r--Source/ThirdParty/glu/libtess/tessmono.h78
-rw-r--r--Source/ThirdParty/gtest/CHANGES98
-rw-r--r--Source/ThirdParty/gtest/CMakeLists.txt384
-rw-r--r--Source/ThirdParty/gtest/CONTRIBUTORS36
-rw-r--r--Source/ThirdParty/gtest/COPYING28
-rw-r--r--Source/ThirdParty/gtest/Makefile.am284
-rw-r--r--Source/ThirdParty/gtest/README417
-rw-r--r--Source/ThirdParty/gtest/README.WebKit13
-rw-r--r--Source/ThirdParty/gtest/codegear/gtest.cbproj138
-rw-r--r--Source/ThirdParty/gtest/codegear/gtest.groupproj54
-rw-r--r--Source/ThirdParty/gtest/codegear/gtest_all.cc38
-rw-r--r--Source/ThirdParty/gtest/codegear/gtest_link.cc40
-rw-r--r--Source/ThirdParty/gtest/codegear/gtest_main.cbproj82
-rw-r--r--Source/ThirdParty/gtest/codegear/gtest_unittest.cbproj88
-rw-r--r--Source/ThirdParty/gtest/configure.ac67
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest-death-test.h283
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest-message.h230
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest-param-test.h1392
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest-param-test.h.pump457
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest-spi.h232
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest-test-part.h176
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest-typed-test.h259
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest.h2052
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest_pred_impl.h368
-rw-r--r--Source/ThirdParty/gtest/include/gtest/gtest_prod.h58
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-death-test-internal.h275
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-filepath.h210
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-internal.h923
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-linked_ptr.h242
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util-generated.h4820
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util-generated.h.pump301
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util.h619
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-port.h1527
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-string.h350
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-tuple.h968
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-tuple.h.pump336
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-type-util.h3321
-rw-r--r--Source/ThirdParty/gtest/include/gtest/internal/gtest-type-util.h.pump287
-rw-r--r--Source/ThirdParty/gtest/m4/acx_pthread.m4363
-rw-r--r--Source/ThirdParty/gtest/m4/gtest.m474
-rw-r--r--Source/ThirdParty/gtest/make/Makefile80
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest-md.sln45
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest-md.vcproj777
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest.sln45
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest.vcproj237
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest_main-md.vcproj165
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest_main.vcproj165
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest_prod_test-md.vcproj164
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest_prod_test.vcproj164
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest_unittest-md.vcproj147
-rw-r--r--Source/ThirdParty/gtest/msvc/gtest_unittest.vcproj147
-rwxr-xr-xSource/ThirdParty/gtest/run_tests.py60
-rw-r--r--Source/ThirdParty/gtest/samples/prime_tables.h123
-rw-r--r--Source/ThirdParty/gtest/samples/sample1.cc68
-rw-r--r--Source/ThirdParty/gtest/samples/sample1.h43
-rw-r--r--Source/ThirdParty/gtest/samples/sample10_unittest.cc145
-rw-r--r--Source/ThirdParty/gtest/samples/sample1_unittest.cc153
-rw-r--r--Source/ThirdParty/gtest/samples/sample2.cc56
-rw-r--r--Source/ThirdParty/gtest/samples/sample2.h86
-rw-r--r--Source/ThirdParty/gtest/samples/sample2_unittest.cc109
-rw-r--r--Source/ThirdParty/gtest/samples/sample3-inl.h173
-rw-r--r--Source/ThirdParty/gtest/samples/sample3_unittest.cc151
-rw-r--r--Source/ThirdParty/gtest/samples/sample4.cc46
-rw-r--r--Source/ThirdParty/gtest/samples/sample4.h53
-rw-r--r--Source/ThirdParty/gtest/samples/sample4_unittest.cc45
-rw-r--r--Source/ThirdParty/gtest/samples/sample5_unittest.cc199
-rw-r--r--Source/ThirdParty/gtest/samples/sample6_unittest.cc224
-rw-r--r--Source/ThirdParty/gtest/samples/sample7_unittest.cc132
-rw-r--r--Source/ThirdParty/gtest/samples/sample8_unittest.cc173
-rw-r--r--Source/ThirdParty/gtest/samples/sample9_unittest.cc160
-rwxr-xr-xSource/ThirdParty/gtest/scripts/fuse_gtest_files.py250
-rwxr-xr-xSource/ThirdParty/gtest/scripts/gen_gtest_pred_impl.py733
-rwxr-xr-xSource/ThirdParty/gtest/scripts/gtest-config.in274
-rwxr-xr-xSource/ThirdParty/gtest/scripts/pump.py835
-rw-r--r--Source/ThirdParty/gtest/scripts/test/Makefile57
-rwxr-xr-xSource/ThirdParty/gtest/scripts/upload.py1387
-rwxr-xr-xSource/ThirdParty/gtest/scripts/upload_gtest.py78
-rw-r--r--Source/ThirdParty/gtest/src/gtest-all.cc47
-rw-r--r--Source/ThirdParty/gtest/src/gtest-death-test.cc1172
-rw-r--r--Source/ThirdParty/gtest/src/gtest-filepath.cc380
-rw-r--r--Source/ThirdParty/gtest/src/gtest-internal-inl.h1074
-rw-r--r--Source/ThirdParty/gtest/src/gtest-port.cc711
-rw-r--r--Source/ThirdParty/gtest/src/gtest-test-part.cc110
-rw-r--r--Source/ThirdParty/gtest/src/gtest-typed-test.cc110
-rw-r--r--Source/ThirdParty/gtest/src/gtest.cc4704
-rw-r--r--Source/ThirdParty/gtest/src/gtest_main.cc39
-rw-r--r--Source/ThirdParty/gtest/test/gtest-death-test_test.cc1230
-rw-r--r--Source/ThirdParty/gtest/test/gtest-filepath_test.cc690
-rw-r--r--Source/ThirdParty/gtest/test/gtest-linked_ptr_test.cc154
-rw-r--r--Source/ThirdParty/gtest/test/gtest-listener_test.cc313
-rw-r--r--Source/ThirdParty/gtest/test/gtest-message_test.cc167
-rw-r--r--Source/ThirdParty/gtest/test/gtest-options_test.cc212
-rw-r--r--Source/ThirdParty/gtest/test/gtest-param-test2_test.cc65
-rw-r--r--Source/ThirdParty/gtest/test/gtest-param-test_test.cc835
-rw-r--r--Source/ThirdParty/gtest/test/gtest-param-test_test.h55
-rw-r--r--Source/ThirdParty/gtest/test/gtest-port_test.cc1018
-rw-r--r--Source/ThirdParty/gtest/test/gtest-test-part_test.cc208
-rw-r--r--Source/ThirdParty/gtest/test/gtest-tuple_test.cc320
-rw-r--r--Source/ThirdParty/gtest/test/gtest-typed-test2_test.cc45
-rw-r--r--Source/ThirdParty/gtest/test/gtest-typed-test_test.cc360
-rw-r--r--Source/ThirdParty/gtest/test/gtest-typed-test_test.h66
-rw-r--r--Source/ThirdParty/gtest/test/gtest-unittest-api_test.cc343
-rw-r--r--Source/ThirdParty/gtest/test/gtest_all_test.cc48
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_break_on_failure_unittest.py218
-rw-r--r--Source/ThirdParty/gtest/test/gtest_break_on_failure_unittest_.cc86
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_color_test.py130
-rw-r--r--Source/ThirdParty/gtest/test/gtest_color_test_.cc71
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_env_var_test.py105
-rw-r--r--Source/ThirdParty/gtest/test/gtest_env_var_test_.cc126
-rw-r--r--Source/ThirdParty/gtest/test/gtest_environment_test.cc186
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_filter_unittest.py633
-rw-r--r--Source/ThirdParty/gtest/test/gtest_filter_unittest_.cc140
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_help_test.py169
-rw-r--r--Source/ThirdParty/gtest/test/gtest_help_test_.cc46
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_list_tests_unittest.py177
-rw-r--r--Source/ThirdParty/gtest/test/gtest_list_tests_unittest_.cc85
-rw-r--r--Source/ThirdParty/gtest/test/gtest_main_unittest.cc45
-rw-r--r--Source/ThirdParty/gtest/test/gtest_nc.cc234
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_nc_test.py106
-rw-r--r--Source/ThirdParty/gtest/test/gtest_no_test_unittest.cc54
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_output_test.py327
-rw-r--r--Source/ThirdParty/gtest/test/gtest_output_test_.cc1135
-rw-r--r--Source/ThirdParty/gtest/test/gtest_output_test_golden_lin.txt696
-rw-r--r--Source/ThirdParty/gtest/test/gtest_output_test_golden_win.txt605
-rw-r--r--Source/ThirdParty/gtest/test/gtest_pred_impl_unittest.cc2432
-rw-r--r--Source/ThirdParty/gtest/test/gtest_prod_test.cc57
-rw-r--r--Source/ThirdParty/gtest/test/gtest_repeat_test.cc253
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_shuffle_test.py325
-rw-r--r--Source/ThirdParty/gtest/test/gtest_shuffle_test_.cc104
-rw-r--r--Source/ThirdParty/gtest/test/gtest_sole_header_test.cc57
-rw-r--r--Source/ThirdParty/gtest/test/gtest_stress_test.cc257
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_test_utils.py309
-rw-r--r--Source/ThirdParty/gtest/test/gtest_throw_on_failure_ex_test.cc92
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_throw_on_failure_test.py171
-rw-r--r--Source/ThirdParty/gtest/test/gtest_throw_on_failure_test_.cc56
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_uninitialized_test.py70
-rw-r--r--Source/ThirdParty/gtest/test/gtest_uninitialized_test_.cc43
-rw-r--r--Source/ThirdParty/gtest/test/gtest_unittest.cc6718
-rw-r--r--Source/ThirdParty/gtest/test/gtest_xml_outfile1_test_.cc49
-rw-r--r--Source/ThirdParty/gtest/test/gtest_xml_outfile2_test_.cc49
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_xml_outfiles_test.py132
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_xml_output_unittest.py224
-rw-r--r--Source/ThirdParty/gtest/test/gtest_xml_output_unittest_.cc145
-rwxr-xr-xSource/ThirdParty/gtest/test/gtest_xml_test_utils.py172
-rw-r--r--Source/ThirdParty/gtest/test/production.cc36
-rw-r--r--Source/ThirdParty/gtest/test/production.h55
-rwxr-xr-xSource/ThirdParty/gtest/test/run_tests_util.py466
-rwxr-xr-xSource/ThirdParty/gtest/test/run_tests_util_test.py676
-rw-r--r--Source/ThirdParty/gtest/xcode/Config/CompilerVersion.xcconfig84
-rw-r--r--Source/ThirdParty/gtest/xcode/Config/DebugProject.xcconfig35
-rw-r--r--Source/ThirdParty/gtest/xcode/Config/FrameworkTarget.xcconfig17
-rw-r--r--Source/ThirdParty/gtest/xcode/Config/General.xcconfig68
-rw-r--r--Source/ThirdParty/gtest/xcode/Config/ProductionProject.xcconfig16
-rw-r--r--Source/ThirdParty/gtest/xcode/Config/ReleaseProject.xcconfig37
-rw-r--r--Source/ThirdParty/gtest/xcode/Config/StaticLibraryTarget.xcconfig18
-rw-r--r--Source/ThirdParty/gtest/xcode/Config/TestTarget.xcconfig8
-rw-r--r--Source/ThirdParty/gtest/xcode/Makefile2
-rw-r--r--Source/ThirdParty/gtest/xcode/Resources/Info.plist30
-rw-r--r--Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/Info.plist28
-rw-r--r--Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj457
-rw-r--r--Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/runtests.sh62
-rw-r--r--Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget.cc63
-rw-r--r--Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget.h59
-rw-r--r--Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget_test.cc68
-rw-r--r--Source/ThirdParty/gtest/xcode/Scripts/runtests.sh65
-rw-r--r--Source/ThirdParty/gtest/xcode/Scripts/versiongenerate.py100
-rw-r--r--Source/ThirdParty/gtest/xcode/gtest.xcodeproj/project.pbxproj1163
-rw-r--r--Source/ThirdParty/gyp/AUTHORS5
-rw-r--r--Source/ThirdParty/gyp/DEPS8
-rw-r--r--Source/ThirdParty/gyp/LICENSE27
-rw-r--r--Source/ThirdParty/gyp/MANIFEST21
-rwxr-xr-xSource/ThirdParty/gyp/PRESUBMIT.py53
-rw-r--r--Source/ThirdParty/gyp/README.WebKit1
-rw-r--r--Source/ThirdParty/gyp/codereview.settings10
-rwxr-xr-xSource/ThirdParty/gyp/gyp18
-rwxr-xr-xSource/ThirdParty/gyp/gyp.bat5
-rw-r--r--Source/ThirdParty/gyp/gyp_dummy.c7
-rwxr-xr-xSource/ThirdParty/gyp/gyptest.py255
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/MSVSNew.py341
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/MSVSProject.py245
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/MSVSSettings.py980
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/MSVSSettings_test.py1478
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/MSVSToolFile.py81
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/MSVSUserFile.py182
-rwxr-xr-xSource/ThirdParty/gyp/pylib/gyp/MSVSVersion.py200
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/SCons.py200
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/__init__.py461
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/common.py345
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/easy_xml.py121
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/easy_xml_test.py92
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/generator/__init__.py0
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/generator/filelist.py45
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/generator/gypd.py88
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/generator/gypsh.py57
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/generator/make.py1423
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/generator/msvs.py1541
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/generator/scons.py1045
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/generator/xcode.py1201
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/input.py2250
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/system_test.py70
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/xcodeproj_file.py2840
-rw-r--r--Source/ThirdParty/gyp/pylib/gyp/xml_fix.py70
-rwxr-xr-xSource/ThirdParty/gyp/samples/samples81
-rw-r--r--Source/ThirdParty/gyp/samples/samples.bat5
-rwxr-xr-xSource/ThirdParty/gyp/setup.py26
-rw-r--r--Source/ThirdParty/gyp/test/actions-bare/gyptest-bare.py23
-rw-r--r--Source/ThirdParty/gyp/test/actions-bare/src/bare.gyp25
-rw-r--r--Source/ThirdParty/gyp/test/actions-bare/src/bare.py11
-rw-r--r--Source/ThirdParty/gyp/test/actions-multiple/gyptest-all.py42
-rw-r--r--Source/ThirdParty/gyp/test/actions-multiple/src/actions.gyp165
-rw-r--r--Source/ThirdParty/gyp/test/actions-multiple/src/copy.py9
-rw-r--r--Source/ThirdParty/gyp/test/actions-multiple/src/filter.py12
-rw-r--r--Source/ThirdParty/gyp/test/actions-multiple/src/foo.c11
-rw-r--r--Source/ThirdParty/gyp/test/actions-multiple/src/input.txt1
-rw-r--r--Source/ThirdParty/gyp/test/actions-multiple/src/main.c22
-rw-r--r--Source/ThirdParty/gyp/test/actions-subdir/gyptest-action.py26
-rw-r--r--Source/ThirdParty/gyp/test/actions-subdir/src/make-file.py11
-rw-r--r--Source/ThirdParty/gyp/test/actions-subdir/src/none.gyp31
-rw-r--r--Source/ThirdParty/gyp/test/actions-subdir/src/subdir/make-subdir-file.py11
-rw-r--r--Source/ThirdParty/gyp/test/actions-subdir/src/subdir/subdir.gyp28
-rw-r--r--Source/ThirdParty/gyp/test/actions/gyptest-all.py94
-rw-r--r--Source/ThirdParty/gyp/test/actions/gyptest-default.py61
-rw-r--r--Source/ThirdParty/gyp/test/actions/gyptest-errors.py24
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/action_missing_name.gyp24
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/actions.gyp114
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/confirm-dep-files.py16
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir1/counter.py46
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir1/executable.gyp74
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir1/make-prog1.py20
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir1/make-prog2.py20
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir1/program.c12
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir2/make-file.py11
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir2/none.gyp33
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir3/generate_main.py21
-rw-r--r--Source/ThirdParty/gyp/test/actions/src/subdir3/null_input.gyp29
-rw-r--r--Source/ThirdParty/gyp/test/additional-targets/gyptest-additional.py55
-rw-r--r--Source/ThirdParty/gyp/test/additional-targets/src/all.gyp13
-rw-r--r--Source/ThirdParty/gyp/test/additional-targets/src/dir1/actions.gyp56
-rw-r--r--Source/ThirdParty/gyp/test/additional-targets/src/dir1/emit.py11
-rw-r--r--Source/ThirdParty/gyp/test/additional-targets/src/dir1/lib1.c6
-rw-r--r--Source/ThirdParty/gyp/test/assembly/gyptest-assembly.py31
-rw-r--r--Source/ThirdParty/gyp/test/assembly/src/as.bat4
-rw-r--r--Source/ThirdParty/gyp/test/assembly/src/assembly.gyp59
-rw-r--r--Source/ThirdParty/gyp/test/assembly/src/lib1.S10
-rw-r--r--Source/ThirdParty/gyp/test/assembly/src/lib1.c3
-rw-r--r--Source/ThirdParty/gyp/test/assembly/src/program.c12
-rw-r--r--Source/ThirdParty/gyp/test/builddir/gyptest-all.py77
-rw-r--r--Source/ThirdParty/gyp/test/builddir/gyptest-default.py77
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/builddir.gypi21
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/func1.c6
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/func2.c6
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/func3.c6
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/func4.c6
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/func5.c6
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/prog1.c10
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/prog1.gyp30
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/subdir2/prog2.c10
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/subdir2/prog2.gyp19
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/prog3.c10
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp19
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c10
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp19
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c10
-rw-r--r--Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp19
-rw-r--r--Source/ThirdParty/gyp/test/cflags/cflags.c15
-rw-r--r--Source/ThirdParty/gyp/test/cflags/cflags.gyp16
-rw-r--r--Source/ThirdParty/gyp/test/cflags/gyptest-cflags.py65
-rw-r--r--Source/ThirdParty/gyp/test/compilable/gyptest-headers.py29
-rw-r--r--Source/ThirdParty/gyp/test/compilable/src/headers.gyp26
-rw-r--r--Source/ThirdParty/gyp/test/compilable/src/lib1.cpp7
-rw-r--r--Source/ThirdParty/gyp/test/compilable/src/lib1.hpp6
-rw-r--r--Source/ThirdParty/gyp/test/compilable/src/program.cpp9
-rw-r--r--Source/ThirdParty/gyp/test/configurations/basics/configurations.c15
-rw-r--r--Source/ThirdParty/gyp/test/configurations/basics/configurations.gyp32
-rw-r--r--Source/ThirdParty/gyp/test/configurations/basics/gyptest-configurations.py29
-rw-r--r--Source/ThirdParty/gyp/test/configurations/inheritance/configurations.c21
-rw-r--r--Source/ThirdParty/gyp/test/configurations/inheritance/configurations.gyp40
-rw-r--r--Source/ThirdParty/gyp/test/configurations/inheritance/gyptest-inheritance.py33
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/actions.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/all_dependent_settings.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/configurations.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/dependencies.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/direct_dependent_settings.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/gyptest-configurations.py38
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/libraries.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/link_settings.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/sources.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/target_name.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/invalid/type.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/configurations/target_platform/configurations.gyp58
-rw-r--r--Source/ThirdParty/gyp/test/configurations/target_platform/front.c8
-rw-r--r--Source/ThirdParty/gyp/test/configurations/target_platform/gyptest-target_platform.py40
-rw-r--r--Source/ThirdParty/gyp/test/configurations/target_platform/left.c3
-rw-r--r--Source/ThirdParty/gyp/test/configurations/target_platform/right.c3
-rw-r--r--Source/ThirdParty/gyp/test/configurations/x64/configurations.c12
-rw-r--r--Source/ThirdParty/gyp/test/configurations/x64/configurations.gyp26
-rw-r--r--Source/ThirdParty/gyp/test/configurations/x64/gyptest-x86.py29
-rw-r--r--Source/ThirdParty/gyp/test/copies-link/gyptest-copies-link.py21
-rw-r--r--Source/ThirdParty/gyp/test/copies-link/src/copies-link.gyp61
-rw-r--r--Source/ThirdParty/gyp/test/copies-link/src/copy.py21
-rw-r--r--Source/ThirdParty/gyp/test/copies-link/src/func1.c5
-rw-r--r--Source/ThirdParty/gyp/test/copies-link/src/main.c9
-rw-r--r--Source/ThirdParty/gyp/test/copies/gyptest-all.py40
-rw-r--r--Source/ThirdParty/gyp/test/copies/gyptest-default.py40
-rw-r--r--Source/ThirdParty/gyp/test/copies/src/copies.gyp70
-rw-r--r--Source/ThirdParty/gyp/test/copies/src/directory/file31
-rw-r--r--Source/ThirdParty/gyp/test/copies/src/directory/file41
-rw-r--r--Source/ThirdParty/gyp/test/copies/src/directory/subdir/file51
-rw-r--r--Source/ThirdParty/gyp/test/copies/src/file11
-rw-r--r--Source/ThirdParty/gyp/test/copies/src/file21
-rw-r--r--Source/ThirdParty/gyp/test/copies/src/parentdir/subdir/file61
-rw-r--r--Source/ThirdParty/gyp/test/cxxflags/cxxflags.cc15
-rw-r--r--Source/ThirdParty/gyp/test/cxxflags/cxxflags.gyp16
-rw-r--r--Source/ThirdParty/gyp/test/cxxflags/gyptest-cxxflags.py65
-rw-r--r--Source/ThirdParty/gyp/test/defines-escaping/defines-escaping.c11
-rw-r--r--Source/ThirdParty/gyp/test/defines-escaping/defines-escaping.gyp19
-rw-r--r--Source/ThirdParty/gyp/test/defines-escaping/gyptest-defines-escaping.py182
-rw-r--r--Source/ThirdParty/gyp/test/defines/defines-env.gyp22
-rw-r--r--Source/ThirdParty/gyp/test/defines/defines.c14
-rw-r--r--Source/ThirdParty/gyp/test/defines/defines.gyp36
-rw-r--r--Source/ThirdParty/gyp/test/defines/gyptest-define-override.py34
-rw-r--r--Source/ThirdParty/gyp/test/defines/gyptest-defines-env-regyp.py49
-rw-r--r--Source/ThirdParty/gyp/test/defines/gyptest-defines-env.py85
-rw-r--r--Source/ThirdParty/gyp/test/defines/gyptest-defines.py25
-rwxr-xr-xSource/ThirdParty/gyp/test/dependencies/a.c9
-rwxr-xr-xSource/ThirdParty/gyp/test/dependencies/b/b.c3
-rwxr-xr-xSource/ThirdParty/gyp/test/dependencies/b/b.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/dependencies/c/c.c4
-rw-r--r--Source/ThirdParty/gyp/test/dependencies/c/c.gyp22
-rw-r--r--Source/ThirdParty/gyp/test/dependencies/c/d.c3
-rw-r--r--Source/ThirdParty/gyp/test/dependencies/extra_targets.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/dependencies/gyptest-extra-targets.py21
-rwxr-xr-xSource/ThirdParty/gyp/test/dependencies/gyptest-lib-only.py33
-rwxr-xr-xSource/ThirdParty/gyp/test/dependencies/lib_only.gyp16
-rw-r--r--Source/ThirdParty/gyp/test/dependency-copy/gyptest-copy.py26
-rw-r--r--Source/ThirdParty/gyp/test/dependency-copy/src/copies.gyp25
-rw-r--r--Source/ThirdParty/gyp/test/dependency-copy/src/file1.c7
-rw-r--r--Source/ThirdParty/gyp/test/dependency-copy/src/file2.c7
-rw-r--r--Source/ThirdParty/gyp/test/exclusion/exclusion.gyp23
-rw-r--r--Source/ThirdParty/gyp/test/exclusion/gyptest-exclusion.py22
-rw-r--r--Source/ThirdParty/gyp/test/exclusion/hello.c15
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/actions.gyp16
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/subdir1/actions-out/README.txt4
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/subdir1/executable.gyp44
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/subdir1/make-prog1.py20
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/subdir1/make-prog2.py20
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/subdir1/program.c12
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/subdir2/actions-out/README.txt4
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/subdir2/make-file.py11
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/actions/subdir2/none.gyp31
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/copies/copies-out/README.txt4
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/copies/copies.gyp50
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/copies/file11
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/copies/file21
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/copies/subdir/copies-out/README.txt4
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/copies/subdir/file31
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/copies/subdir/file41
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/copies/subdir/subdir.gyp32
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/gyptest-actions.py57
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/gyptest-copies.py57
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/gyptest-relocate.py59
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/gyptest-rules.py58
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/gyptest-subdir2-deep.py36
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/gyptest-top-all.py53
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/copy-file.py12
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/rules.gyp16
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir1/define3.in01
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir1/define4.in01
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir1/executable.gyp59
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir1/function1.in16
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir1/function2.in16
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir1/program.c18
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file1.in01
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file2.in01
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file3.in11
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file4.in11
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir2/none.gyp49
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/rules/subdir2/rules-out/README.txt4
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/inc.h1
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/inc1/include1.h1
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/prog1.c18
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/prog1.gyp28
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.c7
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.h1
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir2/inc2/include2.h1
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir2/prog2.c18
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir2/prog2.gyp28
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir3/inc3/include3.h1
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir3/prog3.c18
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/subdir3/prog3.gyp25
-rw-r--r--Source/ThirdParty/gyp/test/generator-output/src/symroot.gypi16
-rw-r--r--Source/ThirdParty/gyp/test/hello/gyptest-all.py24
-rw-r--r--Source/ThirdParty/gyp/test/hello/gyptest-default.py24
-rw-r--r--Source/ThirdParty/gyp/test/hello/gyptest-disable-regyp.py32
-rw-r--r--Source/ThirdParty/gyp/test/hello/gyptest-regyp.py32
-rwxr-xr-xSource/ThirdParty/gyp/test/hello/gyptest-target.py24
-rw-r--r--Source/ThirdParty/gyp/test/hello/hello.c11
-rw-r--r--Source/ThirdParty/gyp/test/hello/hello.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/hello/hello2.c11
-rw-r--r--Source/ThirdParty/gyp/test/hello/hello2.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py44
-rw-r--r--Source/ThirdParty/gyp/test/home_dot_gyp/gyptest-home-includes.py30
-rw-r--r--Source/ThirdParty/gyp/test/home_dot_gyp/home/.gyp/include.gypi5
-rw-r--r--Source/ThirdParty/gyp/test/home_dot_gyp/home2/.gyp/include.gypi5
-rw-r--r--Source/ThirdParty/gyp/test/home_dot_gyp/src/all.gyp22
-rw-r--r--Source/ThirdParty/gyp/test/home_dot_gyp/src/printfoo.c7
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/gyptest-all.py46
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/gyptest-default.py46
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/inc.h1
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/inc1/include1.h1
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/includes.c19
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/includes.gyp27
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/shadow1/shadow.h1
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/shadow2/shadow.h1
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/subdir/inc.h1
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/subdir/inc2/include2.h1
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/subdir/subdir_includes.c14
-rw-r--r--Source/ThirdParty/gyp/test/include_dirs/src/subdir/subdir_includes.gyp20
-rw-r--r--Source/ThirdParty/gyp/test/lib/README.txt17
-rw-r--r--Source/ThirdParty/gyp/test/lib/TestCmd.py1591
-rw-r--r--Source/ThirdParty/gyp/test/lib/TestCommon.py581
-rw-r--r--Source/ThirdParty/gyp/test/lib/TestGyp.py724
-rw-r--r--Source/ThirdParty/gyp/test/library/gyptest-shared-obj-install-path.py37
-rw-r--r--Source/ThirdParty/gyp/test/library/gyptest-shared.py84
-rw-r--r--Source/ThirdParty/gyp/test/library/gyptest-static.py84
-rw-r--r--Source/ThirdParty/gyp/test/library/src/lib1.c10
-rw-r--r--Source/ThirdParty/gyp/test/library/src/lib1_moveable.c10
-rw-r--r--Source/ThirdParty/gyp/test/library/src/lib2.c10
-rw-r--r--Source/ThirdParty/gyp/test/library/src/lib2_moveable.c10
-rw-r--r--Source/ThirdParty/gyp/test/library/src/library.gyp58
-rw-r--r--Source/ThirdParty/gyp/test/library/src/program.c15
-rw-r--r--Source/ThirdParty/gyp/test/library/src/shared_dependency.gyp33
-rw-r--r--Source/ThirdParty/gyp/test/link-objects/base.c6
-rw-r--r--Source/ThirdParty/gyp/test/link-objects/extra.c5
-rw-r--r--Source/ThirdParty/gyp/test/link-objects/gyptest-all.py25
-rw-r--r--Source/ThirdParty/gyp/test/link-objects/link-objects.gyp24
-rw-r--r--Source/ThirdParty/gyp/test/make/dependencies.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/make/gyptest-dependencies.py31
-rw-r--r--Source/ThirdParty/gyp/test/make/gyptest-noload.py57
-rw-r--r--Source/ThirdParty/gyp/test/make/main.cc12
-rw-r--r--Source/ThirdParty/gyp/test/make/main.h0
-rw-r--r--Source/ThirdParty/gyp/test/make/noload/all.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/make/noload/lib/shared.c3
-rw-r--r--Source/ThirdParty/gyp/test/make/noload/lib/shared.gyp16
-rw-r--r--Source/ThirdParty/gyp/test/make/noload/lib/shared.h1
-rw-r--r--Source/ThirdParty/gyp/test/make/noload/main.c9
-rw-r--r--Source/ThirdParty/gyp/test/module/gyptest-default.py28
-rw-r--r--Source/ThirdParty/gyp/test/module/src/lib1.c10
-rw-r--r--Source/ThirdParty/gyp/test/module/src/lib2.c10
-rw-r--r--Source/ThirdParty/gyp/test/module/src/module.gyp55
-rw-r--r--Source/ThirdParty/gyp/test/module/src/program.c111
-rw-r--r--Source/ThirdParty/gyp/test/msvs/express/base/base.gyp22
-rw-r--r--Source/ThirdParty/gyp/test/msvs/express/express.gyp19
-rw-r--r--Source/ThirdParty/gyp/test/msvs/express/gyptest-express.py29
-rw-r--r--Source/ThirdParty/gyp/test/msvs/precompiled/gyptest-all.py23
-rw-r--r--Source/ThirdParty/gyp/test/msvs/precompiled/hello.c14
-rw-r--r--Source/ThirdParty/gyp/test/msvs/precompiled/hello.gyp19
-rw-r--r--Source/ThirdParty/gyp/test/msvs/precompiled/hello2.c13
-rw-r--r--Source/ThirdParty/gyp/test/msvs/precompiled/precomp.c8
-rw-r--r--Source/ThirdParty/gyp/test/multiple-targets/gyptest-all.py35
-rw-r--r--Source/ThirdParty/gyp/test/multiple-targets/gyptest-default.py35
-rw-r--r--Source/ThirdParty/gyp/test/multiple-targets/src/common.c7
-rw-r--r--Source/ThirdParty/gyp/test/multiple-targets/src/multiple.gyp24
-rw-r--r--Source/ThirdParty/gyp/test/multiple-targets/src/prog1.c10
-rw-r--r--Source/ThirdParty/gyp/test/multiple-targets/src/prog2.c10
-rw-r--r--Source/ThirdParty/gyp/test/no-output/gyptest-no-output.py19
-rw-r--r--Source/ThirdParty/gyp/test/no-output/src/nooutput.gyp17
-rw-r--r--Source/ThirdParty/gyp/test/product/gyptest-product.py43
-rw-r--r--Source/ThirdParty/gyp/test/product/hello.c15
-rw-r--r--Source/ThirdParty/gyp/test/product/product.gyp128
-rw-r--r--Source/ThirdParty/gyp/test/rules-rebuild/gyptest-all.py70
-rw-r--r--Source/ThirdParty/gyp/test/rules-rebuild/gyptest-default.py70
-rw-r--r--Source/ThirdParty/gyp/test/rules-rebuild/src/main.c12
-rw-r--r--Source/ThirdParty/gyp/test/rules-rebuild/src/make-sources.py15
-rw-r--r--Source/ThirdParty/gyp/test/rules-rebuild/src/prog1.in7
-rw-r--r--Source/ThirdParty/gyp/test/rules-rebuild/src/prog2.in7
-rw-r--r--Source/ThirdParty/gyp/test/rules-rebuild/src/same_target.gyp31
-rw-r--r--Source/ThirdParty/gyp/test/rules/gyptest-all.py50
-rw-r--r--Source/ThirdParty/gyp/test/rules/gyptest-default.py50
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/actions.gyp19
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/copy-file.py11
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir1/executable.gyp37
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir1/function1.in6
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir1/function2.in6
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir1/program.c12
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir2/file1.in1
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir2/file2.in1
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir2/never_used.gyp31
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir2/no_inputs.gyp32
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir2/none.gyp33
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir3/executable2.gyp37
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir3/function3.in6
-rw-r--r--Source/ThirdParty/gyp/test/rules/src/subdir3/program.c10
-rw-r--r--Source/ThirdParty/gyp/test/same-gyp-name/gyptest-all.py34
-rw-r--r--Source/ThirdParty/gyp/test/same-gyp-name/gyptest-default.py34
-rw-r--r--Source/ThirdParty/gyp/test/same-gyp-name/src/all.gyp16
-rw-r--r--Source/ThirdParty/gyp/test/same-gyp-name/src/subdir1/executable.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/same-gyp-name/src/subdir1/main1.cc6
-rw-r--r--Source/ThirdParty/gyp/test/same-gyp-name/src/subdir2/executable.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/same-gyp-name/src/subdir2/main2.cc6
-rw-r--r--Source/ThirdParty/gyp/test/same-name/gyptest-all.py34
-rw-r--r--Source/ThirdParty/gyp/test/same-name/gyptest-default.py34
-rw-r--r--Source/ThirdParty/gyp/test/same-name/src/all.gyp38
-rw-r--r--Source/ThirdParty/gyp/test/same-name/src/func.c6
-rw-r--r--Source/ThirdParty/gyp/test/same-name/src/prog1.c16
-rw-r--r--Source/ThirdParty/gyp/test/same-name/src/prog2.c16
-rw-r--r--Source/ThirdParty/gyp/test/same-name/src/subdir1/func.c6
-rw-r--r--Source/ThirdParty/gyp/test/same-name/src/subdir2/func.c6
-rw-r--r--Source/ThirdParty/gyp/test/same-target-name/gyptest-same-target-name.py18
-rw-r--r--Source/ThirdParty/gyp/test/same-target-name/src/all.gyp16
-rw-r--r--Source/ThirdParty/gyp/test/same-target-name/src/executable1.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/same-target-name/src/executable2.gyp15
-rwxr-xr-xSource/ThirdParty/gyp/test/scons_tools/gyptest-tools.py26
-rw-r--r--Source/ThirdParty/gyp/test/scons_tools/site_scons/site_tools/this_tool.py10
-rw-r--r--Source/ThirdParty/gyp/test/scons_tools/tools.c13
-rw-r--r--Source/ThirdParty/gyp/test/scons_tools/tools.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/sibling/gyptest-all.py39
-rw-r--r--Source/ThirdParty/gyp/test/sibling/gyptest-relocate.py41
-rw-r--r--Source/ThirdParty/gyp/test/sibling/src/prog1/prog1.c7
-rw-r--r--Source/ThirdParty/gyp/test/sibling/src/prog1/prog1.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/sibling/src/prog2/prog2.c7
-rw-r--r--Source/ThirdParty/gyp/test/sibling/src/prog2/prog2.gyp15
-rwxr-xr-xSource/ThirdParty/gyp/test/small/gyptest-small.py49
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/gyptest-SYMROOT-all.py36
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/gyptest-SYMROOT-default.py37
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir-all.py33
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir-default.py32
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir2-deep.py25
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/gyptest-top-all.py43
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/gyptest-top-default.py43
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/src/prog1.c7
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/src/prog1.gyp21
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/src/subdir/prog2.c7
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/src/subdir/prog2.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/src/subdir/subdir2/prog3.c7
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/subdirectory/src/symroot.gypi16
-rw-r--r--Source/ThirdParty/gyp/test/toolsets/gyptest-toolsets.py23
-rw-r--r--Source/ThirdParty/gyp/test/toolsets/main.cc11
-rw-r--r--Source/ThirdParty/gyp/test/toolsets/toolsets.cc11
-rw-r--r--Source/ThirdParty/gyp/test/toolsets/toolsets.gyp38
-rw-r--r--Source/ThirdParty/gyp/test/toplevel-dir/gyptest-toplevel-dir.py31
-rw-r--r--Source/ThirdParty/gyp/test/toplevel-dir/src/sub1/main.gyp18
-rw-r--r--Source/ThirdParty/gyp/test/toplevel-dir/src/sub1/prog1.c7
-rw-r--r--Source/ThirdParty/gyp/test/toplevel-dir/src/sub2/prog2.c7
-rw-r--r--Source/ThirdParty/gyp/test/toplevel-dir/src/sub2/prog2.gyp15
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gyp128
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gyp.stdout405
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gypd.golden72
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/commands.gyp84
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/commands.gyp.ignore-env.stdout254
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/commands.gyp.stdout254
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/commands.gypd.golden54
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/commands.gypi16
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/gyptest-commands-ignore-env.py51
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/gyptest-commands-repeated.py45
-rw-r--r--Source/ThirdParty/gyp/test/variables/commands/gyptest-commands.py44
-rwxr-xr-xSource/ThirdParty/gyp/test/variables/commands/update_golden11
-rw-r--r--Source/ThirdParty/gyp/test/variables/filelist/filelist.gyp.stdout174
-rw-r--r--Source/ThirdParty/gyp/test/variables/filelist/filelist.gypd.golden43
-rw-r--r--Source/ThirdParty/gyp/test/variables/filelist/gyptest-filelist.py55
-rw-r--r--Source/ThirdParty/gyp/test/variables/filelist/src/filelist.gyp93
-rwxr-xr-xSource/ThirdParty/gyp/test/variables/filelist/update_golden8
-rw-r--r--Source/ThirdParty/gyp/test/variants/gyptest-variants.py45
-rw-r--r--Source/ThirdParty/gyp/test/variants/src/variants.c13
-rw-r--r--Source/ThirdParty/gyp/test/variants/src/variants.gyp27
-rw-r--r--Source/ThirdParty/gyp/tools/README15
-rw-r--r--Source/ThirdParty/gyp/tools/pretty_gyp.py142
-rwxr-xr-xSource/ThirdParty/gyp/tools/pretty_sln.py167
-rwxr-xr-xSource/ThirdParty/gyp/tools/pretty_vcproj.py316
-rw-r--r--Source/ThirdParty/mt19937ar.c170
-rw-r--r--Source/ThirdParty/qunit/.gitignore6
-rw-r--r--Source/ThirdParty/qunit/README.WebKit5
-rw-r--r--Source/ThirdParty/qunit/README.md27
-rw-r--r--Source/ThirdParty/qunit/package.json21
-rw-r--r--Source/ThirdParty/qunit/qunit/qunit.css225
-rw-r--r--Source/ThirdParty/qunit/qunit/qunit.js1448
-rw-r--r--Source/ThirdParty/qunit/test/headless.html24
-rw-r--r--Source/ThirdParty/qunit/test/index.html19
-rw-r--r--Source/ThirdParty/qunit/test/logs.html17
-rw-r--r--Source/ThirdParty/qunit/test/logs.js150
-rw-r--r--Source/ThirdParty/qunit/test/same.js1421
-rw-r--r--Source/ThirdParty/qunit/test/test.js324
792 files changed, 170166 insertions, 0 deletions
diff --git a/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj b/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..8e80ad78e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/ANGLE.xcodeproj/project.pbxproj
@@ -0,0 +1,662 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 90D9B10212E11DCB002D4255 /* Compiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90D9B0F912E11DCB002D4255 /* Compiler.cpp */; };
+ 90D9B10312E11DCB002D4255 /* ExtensionBehavior.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D9B0FA12E11DCB002D4255 /* ExtensionBehavior.h */; };
+ 90D9B10412E11DCB002D4255 /* glslang_lex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90D9B0FB12E11DCB002D4255 /* glslang_lex.cpp */; };
+ 90D9B10512E11DCB002D4255 /* glslang_tab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90D9B0FC12E11DCB002D4255 /* glslang_tab.cpp */; };
+ 90D9B10612E11DCB002D4255 /* glslang_tab.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D9B0FD12E11DCB002D4255 /* glslang_tab.h */; };
+ 90D9B10712E11DCB002D4255 /* glslang.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D9B0FE12E11DCB002D4255 /* glslang.h */; };
+ 90D9B10912E11DCB002D4255 /* SearchSymbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90D9B10012E11DCB002D4255 /* SearchSymbol.cpp */; };
+ 90D9B10A12E11DCB002D4255 /* SearchSymbol.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D9B10112E11DCB002D4255 /* SearchSymbol.h */; };
+ 90D9B11312E11DD6002D4255 /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90D9B10B12E11DD6002D4255 /* util.cpp */; };
+ 90D9B11412E11DD6002D4255 /* util.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D9B10C12E11DD6002D4255 /* util.h */; };
+ 90D9B11512E11DD6002D4255 /* ValidateLimitations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90D9B10D12E11DD6002D4255 /* ValidateLimitations.cpp */; };
+ 90D9B11612E11DD6002D4255 /* ValidateLimitations.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D9B10E12E11DD6002D4255 /* ValidateLimitations.h */; };
+ 90D9B11712E11DD6002D4255 /* VariableInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90D9B10F12E11DD6002D4255 /* VariableInfo.cpp */; };
+ 90D9B11812E11DD6002D4255 /* VariableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D9B11012E11DD6002D4255 /* VariableInfo.h */; };
+ 90D9B11912E11DD6002D4255 /* VersionGLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 90D9B11112E11DD6002D4255 /* VersionGLSL.cpp */; };
+ 90D9B11A12E11DD6002D4255 /* VersionGLSL.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D9B11212E11DD6002D4255 /* VersionGLSL.h */; };
+ A0AABE2C13AFE81000F2EBD1 /* ForLoopUnroll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A0AABE2A13AFE81000F2EBD1 /* ForLoopUnroll.cpp */; };
+ A0AABE2D13AFE81000F2EBD1 /* ForLoopUnroll.h in Headers */ = {isa = PBXBuildFile; fileRef = A0AABE2B13AFE81000F2EBD1 /* ForLoopUnroll.h */; };
+ A0AABE3013AFE83000F2EBD1 /* MapLongVariableNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A0AABE2E13AFE83000F2EBD1 /* MapLongVariableNames.cpp */; };
+ A0AABE3113AFE83000F2EBD1 /* MapLongVariableNames.h in Headers */ = {isa = PBXBuildFile; fileRef = A0AABE2F13AFE83000F2EBD1 /* MapLongVariableNames.h */; };
+ A0AABE3413AFE84700F2EBD1 /* OutputGLSLBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A0AABE3213AFE84700F2EBD1 /* OutputGLSLBase.cpp */; };
+ A0AABE3513AFE84700F2EBD1 /* OutputGLSLBase.h in Headers */ = {isa = PBXBuildFile; fileRef = A0AABE3313AFE84700F2EBD1 /* OutputGLSLBase.h */; };
+ A0AABE4413AFE94500F2EBD1 /* OutputESSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A0AABE4213AFE94500F2EBD1 /* OutputESSL.cpp */; };
+ A0AABE4513AFE94500F2EBD1 /* OutputESSL.h in Headers */ = {isa = PBXBuildFile; fileRef = A0AABE4313AFE94500F2EBD1 /* OutputESSL.h */; };
+ A0AABE4813AFE96100F2EBD1 /* TranslatorESSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A0AABE4613AFE96100F2EBD1 /* TranslatorESSL.cpp */; };
+ A0AABE4913AFE96100F2EBD1 /* TranslatorESSL.h in Headers */ = {isa = PBXBuildFile; fileRef = A0AABE4713AFE96100F2EBD1 /* TranslatorESSL.h */; };
+ FB39D2711200F35A00088E69 /* CodeGenGLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2221200F35A00088E69 /* CodeGenGLSL.cpp */; };
+ FB39D2751200F35A00088E69 /* debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2261200F35A00088E69 /* debug.cpp */; };
+ FB39D2791200F35A00088E69 /* InfoSink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D22A1200F35A00088E69 /* InfoSink.cpp */; };
+ FB39D27B1200F35A00088E69 /* Initialize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D22C1200F35A00088E69 /* Initialize.cpp */; };
+ FB39D27D1200F35A00088E69 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D22E1200F35A00088E69 /* InitializeDll.cpp */; };
+ FB39D2811200F35A00088E69 /* Intermediate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2321200F35A00088E69 /* Intermediate.cpp */; };
+ FB39D2831200F35A00088E69 /* intermOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2341200F35A00088E69 /* intermOut.cpp */; };
+ FB39D2841200F35A00088E69 /* IntermTraverse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2351200F35A00088E69 /* IntermTraverse.cpp */; };
+ FB39D2881200F35A00088E69 /* ossource_posix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2391200F35A00088E69 /* ossource_posix.cpp */; };
+ FB39D28A1200F35A00088E69 /* OutputGLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D23B1200F35A00088E69 /* OutputGLSL.cpp */; };
+ FB39D28E1200F35A00088E69 /* parseConst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D23F1200F35A00088E69 /* parseConst.cpp */; };
+ FB39D28F1200F35A00088E69 /* ParseHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2401200F35A00088E69 /* ParseHelper.cpp */; };
+ FB39D2911200F35A00088E69 /* PoolAlloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2421200F35A00088E69 /* PoolAlloc.cpp */; };
+ FB39D2931200F35A00088E69 /* atom.c in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2451200F35A00088E69 /* atom.c */; };
+ FB39D2961200F35A00088E69 /* cpp.c in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2481200F35A00088E69 /* cpp.c */; };
+ FB39D2981200F35A00088E69 /* cppstruct.c in Sources */ = {isa = PBXBuildFile; fileRef = FB39D24A1200F35A00088E69 /* cppstruct.c */; };
+ FB39D2991200F35A00088E69 /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = FB39D24B1200F35A00088E69 /* memory.c */; };
+ FB39D29D1200F35A00088E69 /* scanner.c in Sources */ = {isa = PBXBuildFile; fileRef = FB39D24F1200F35A00088E69 /* scanner.c */; };
+ FB39D2A01200F35A00088E69 /* symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2521200F35A00088E69 /* symbols.c */; };
+ FB39D2A21200F35A00088E69 /* tokens.c in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2541200F35A00088E69 /* tokens.c */; };
+ FB39D2A41200F35A00088E69 /* QualifierAlive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2561200F35A00088E69 /* QualifierAlive.cpp */; };
+ FB39D2A61200F35A00088E69 /* RemoveTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2581200F35A00088E69 /* RemoveTree.cpp */; };
+ FB39D2A81200F35A00088E69 /* ShaderLang.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D25A1200F35A00088E69 /* ShaderLang.cpp */; };
+ FB39D2AA1200F35A00088E69 /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D25C1200F35A00088E69 /* SymbolTable.cpp */; };
+ FB39D2AC1200F35A00088E69 /* TranslatorGLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D2681200F35A00088E69 /* TranslatorGLSL.cpp */; };
+ FB39D2B11200F35A00088E69 /* UnfoldSelect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FB39D26D1200F35A00088E69 /* UnfoldSelect.cpp */; };
+ FB39D76E120110FC00088E69 /* ShaderLang.h in Headers */ = {isa = PBXBuildFile; fileRef = FB39D2BF1200F3E600088E69 /* ShaderLang.h */; settings = {ATTRIBUTES = (Public, ); }; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 5D7C59C51208C68B001C873E /* ANGLE.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ANGLE.xcconfig; sourceTree = "<group>"; };
+ 5D7C59C61208C68B001C873E /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
+ 5D7C59C71208C68B001C873E /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = "<group>"; };
+ 90D9B0F912E11DCB002D4255 /* Compiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Compiler.cpp; sourceTree = "<group>"; };
+ 90D9B0FA12E11DCB002D4255 /* ExtensionBehavior.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExtensionBehavior.h; sourceTree = "<group>"; };
+ 90D9B0FB12E11DCB002D4255 /* glslang_lex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glslang_lex.cpp; sourceTree = "<group>"; };
+ 90D9B0FC12E11DCB002D4255 /* glslang_tab.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = glslang_tab.cpp; sourceTree = "<group>"; };
+ 90D9B0FD12E11DCB002D4255 /* glslang_tab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glslang_tab.h; sourceTree = "<group>"; };
+ 90D9B0FE12E11DCB002D4255 /* glslang.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glslang.h; sourceTree = "<group>"; };
+ 90D9B0FF12E11DCB002D4255 /* ossource_nspr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ossource_nspr.cpp; sourceTree = "<group>"; };
+ 90D9B10012E11DCB002D4255 /* SearchSymbol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SearchSymbol.cpp; sourceTree = "<group>"; };
+ 90D9B10112E11DCB002D4255 /* SearchSymbol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchSymbol.h; sourceTree = "<group>"; };
+ 90D9B10B12E11DD6002D4255 /* util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = util.cpp; sourceTree = "<group>"; };
+ 90D9B10C12E11DD6002D4255 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
+ 90D9B10D12E11DD6002D4255 /* ValidateLimitations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ValidateLimitations.cpp; sourceTree = "<group>"; };
+ 90D9B10E12E11DD6002D4255 /* ValidateLimitations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValidateLimitations.h; sourceTree = "<group>"; };
+ 90D9B10F12E11DD6002D4255 /* VariableInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VariableInfo.cpp; sourceTree = "<group>"; };
+ 90D9B11012E11DD6002D4255 /* VariableInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VariableInfo.h; sourceTree = "<group>"; };
+ 90D9B11112E11DD6002D4255 /* VersionGLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VersionGLSL.cpp; sourceTree = "<group>"; };
+ 90D9B11212E11DD6002D4255 /* VersionGLSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VersionGLSL.h; sourceTree = "<group>"; };
+ A0AABE2A13AFE81000F2EBD1 /* ForLoopUnroll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ForLoopUnroll.cpp; sourceTree = "<group>"; };
+ A0AABE2B13AFE81000F2EBD1 /* ForLoopUnroll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ForLoopUnroll.h; sourceTree = "<group>"; };
+ A0AABE2E13AFE83000F2EBD1 /* MapLongVariableNames.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapLongVariableNames.cpp; sourceTree = "<group>"; };
+ A0AABE2F13AFE83000F2EBD1 /* MapLongVariableNames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapLongVariableNames.h; sourceTree = "<group>"; };
+ A0AABE3213AFE84700F2EBD1 /* OutputGLSLBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OutputGLSLBase.cpp; sourceTree = "<group>"; };
+ A0AABE3313AFE84700F2EBD1 /* OutputGLSLBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputGLSLBase.h; sourceTree = "<group>"; };
+ A0AABE4213AFE94500F2EBD1 /* OutputESSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OutputESSL.cpp; sourceTree = "<group>"; };
+ A0AABE4313AFE94500F2EBD1 /* OutputESSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputESSL.h; sourceTree = "<group>"; };
+ A0AABE4613AFE96100F2EBD1 /* TranslatorESSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorESSL.cpp; sourceTree = "<group>"; };
+ A0AABE4713AFE96100F2EBD1 /* TranslatorESSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TranslatorESSL.h; sourceTree = "<group>"; };
+ FB39D0D11200F0E300088E69 /* libANGLE.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libANGLE.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ FB39D1861200F26200088E69 /* BaseTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseTypes.h; sourceTree = "<group>"; };
+ FB39D1871200F26200088E69 /* CodeGenGLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGenGLSL.cpp; sourceTree = "<group>"; };
+ FB39D1881200F26200088E69 /* CodeGenHLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGenHLSL.cpp; sourceTree = "<group>"; };
+ FB39D1891200F26200088E69 /* Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = "<group>"; };
+ FB39D18A1200F26200088E69 /* ConstantUnion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantUnion.h; sourceTree = "<group>"; };
+ FB39D18B1200F26200088E69 /* debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = debug.cpp; sourceTree = "<group>"; };
+ FB39D18C1200F26200088E69 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
+ FB39D18F1200F26200088E69 /* InfoSink.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = InfoSink.cpp; sourceTree = "<group>"; };
+ FB39D1901200F26200088E69 /* InfoSink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InfoSink.h; sourceTree = "<group>"; };
+ FB39D1911200F26200088E69 /* Initialize.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = Initialize.cpp; sourceTree = "<group>"; };
+ FB39D1921200F26200088E69 /* Initialize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Initialize.h; sourceTree = "<group>"; };
+ FB39D1931200F26200088E69 /* InitializeDll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeDll.cpp; sourceTree = "<group>"; };
+ FB39D1941200F26200088E69 /* InitializeDll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeDll.h; sourceTree = "<group>"; };
+ FB39D1951200F26200088E69 /* InitializeGlobals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeGlobals.h; sourceTree = "<group>"; };
+ FB39D1961200F26200088E69 /* InitializeParseContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeParseContext.h; sourceTree = "<group>"; };
+ FB39D1971200F26200088E69 /* Intermediate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = Intermediate.cpp; sourceTree = "<group>"; };
+ FB39D1981200F26200088E69 /* intermediate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = intermediate.h; sourceTree = "<group>"; };
+ FB39D1991200F26200088E69 /* intermOut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = intermOut.cpp; sourceTree = "<group>"; };
+ FB39D19A1200F26200088E69 /* IntermTraverse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = IntermTraverse.cpp; sourceTree = "<group>"; };
+ FB39D19B1200F26200088E69 /* localintermediate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = localintermediate.h; sourceTree = "<group>"; };
+ FB39D19C1200F26200088E69 /* MMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMap.h; sourceTree = "<group>"; };
+ FB39D19D1200F26200088E69 /* osinclude.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osinclude.h; sourceTree = "<group>"; };
+ FB39D19E1200F26200088E69 /* ossource_posix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = ossource_posix.cpp; sourceTree = "<group>"; };
+ FB39D19F1200F26200088E69 /* ossource_win.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = ossource_win.cpp; sourceTree = "<group>"; };
+ FB39D1A01200F26200088E69 /* OutputGLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = OutputGLSL.cpp; sourceTree = "<group>"; };
+ FB39D1A11200F26200088E69 /* OutputGLSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputGLSL.h; sourceTree = "<group>"; };
+ FB39D1A21200F26200088E69 /* OutputHLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = OutputHLSL.cpp; sourceTree = "<group>"; };
+ FB39D1A31200F26200088E69 /* OutputHLSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OutputHLSL.h; sourceTree = "<group>"; };
+ FB39D1A41200F26200088E69 /* parseConst.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = parseConst.cpp; sourceTree = "<group>"; };
+ FB39D1A51200F26200088E69 /* ParseHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = ParseHelper.cpp; sourceTree = "<group>"; };
+ FB39D1A61200F26200088E69 /* ParseHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParseHelper.h; sourceTree = "<group>"; };
+ FB39D1A71200F26200088E69 /* PoolAlloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = PoolAlloc.cpp; sourceTree = "<group>"; };
+ FB39D1A81200F26200088E69 /* PoolAlloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PoolAlloc.h; sourceTree = "<group>"; };
+ FB39D1AA1200F26200088E69 /* atom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atom.c; sourceTree = "<group>"; };
+ FB39D1AB1200F26200088E69 /* atom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = atom.h; sourceTree = "<group>"; };
+ FB39D1AC1200F26200088E69 /* compile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compile.h; sourceTree = "<group>"; };
+ FB39D1AD1200F26200088E69 /* cpp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpp.c; sourceTree = "<group>"; };
+ FB39D1AE1200F26200088E69 /* cpp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpp.h; sourceTree = "<group>"; };
+ FB39D1AF1200F26200088E69 /* cppstruct.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cppstruct.c; sourceTree = "<group>"; };
+ FB39D1B01200F26200088E69 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory.c; sourceTree = "<group>"; };
+ FB39D1B11200F26200088E69 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = "<group>"; };
+ FB39D1B21200F26200088E69 /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
+ FB39D1B31200F26200088E69 /* preprocess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = preprocess.h; sourceTree = "<group>"; };
+ FB39D1B41200F26200088E69 /* scanner.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scanner.c; sourceTree = "<group>"; };
+ FB39D1B51200F26200088E69 /* scanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanner.h; sourceTree = "<group>"; };
+ FB39D1B61200F26200088E69 /* slglobals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slglobals.h; sourceTree = "<group>"; };
+ FB39D1B71200F26200088E69 /* symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = symbols.c; sourceTree = "<group>"; };
+ FB39D1B81200F26200088E69 /* symbols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = symbols.h; sourceTree = "<group>"; };
+ FB39D1B91200F26200088E69 /* tokens.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tokens.c; sourceTree = "<group>"; };
+ FB39D1BA1200F26200088E69 /* tokens.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tokens.h; sourceTree = "<group>"; };
+ FB39D1BB1200F26200088E69 /* QualifierAlive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = QualifierAlive.cpp; sourceTree = "<group>"; };
+ FB39D1BC1200F26200088E69 /* QualifierAlive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QualifierAlive.h; sourceTree = "<group>"; };
+ FB39D1BD1200F26200088E69 /* RemoveTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = RemoveTree.cpp; sourceTree = "<group>"; };
+ FB39D1BE1200F26200088E69 /* RemoveTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoveTree.h; sourceTree = "<group>"; };
+ FB39D1BF1200F26200088E69 /* ShaderLang.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; includeInIndex = 0; path = ShaderLang.cpp; sourceTree = "<group>"; };
+ FB39D1C01200F26200088E69 /* ShHandle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShHandle.h; sourceTree = "<group>"; };
+ FB39D1C11200F26200088E69 /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolTable.cpp; sourceTree = "<group>"; };
+ FB39D1C21200F26200088E69 /* SymbolTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolTable.h; sourceTree = "<group>"; };
+ FB39D1CB1200F26200088E69 /* translator_common.vcproj */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = translator_common.vcproj; sourceTree = "<group>"; };
+ FB39D1CC1200F26200088E69 /* translator_hlsl.vcproj */ = {isa = PBXFileReference; explicitFileType = text.xml; fileEncoding = 4; path = translator_hlsl.vcproj; sourceTree = "<group>"; };
+ FB39D1CD1200F26200088E69 /* TranslatorGLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorGLSL.cpp; sourceTree = "<group>"; };
+ FB39D1CE1200F26200088E69 /* TranslatorGLSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TranslatorGLSL.h; sourceTree = "<group>"; };
+ FB39D1CF1200F26200088E69 /* TranslatorHLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorHLSL.cpp; sourceTree = "<group>"; };
+ FB39D1D01200F26200088E69 /* TranslatorHLSL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TranslatorHLSL.h; sourceTree = "<group>"; };
+ FB39D1D11200F26200088E69 /* Types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = "<group>"; };
+ FB39D1D21200F26200088E69 /* UnfoldSelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.cpp.cpp; path = UnfoldSelect.cpp; sourceTree = "<group>"; };
+ FB39D1D31200F26200088E69 /* UnfoldSelect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnfoldSelect.h; sourceTree = "<group>"; };
+ FB39D2211200F35A00088E69 /* BaseTypes.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = BaseTypes.h; sourceTree = "<group>"; };
+ FB39D2221200F35A00088E69 /* CodeGenGLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGenGLSL.cpp; sourceTree = "<group>"; };
+ FB39D2241200F35A00088E69 /* Common.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = Common.h; sourceTree = "<group>"; };
+ FB39D2251200F35A00088E69 /* ConstantUnion.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = ConstantUnion.h; sourceTree = "<group>"; };
+ FB39D2261200F35A00088E69 /* debug.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debug.cpp; sourceTree = "<group>"; };
+ FB39D2271200F35A00088E69 /* debug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
+ FB39D22A1200F35A00088E69 /* InfoSink.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InfoSink.cpp; sourceTree = "<group>"; };
+ FB39D22B1200F35A00088E69 /* InfoSink.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = InfoSink.h; sourceTree = "<group>"; };
+ FB39D22C1200F35A00088E69 /* Initialize.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Initialize.cpp; sourceTree = "<group>"; };
+ FB39D22D1200F35A00088E69 /* Initialize.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = Initialize.h; sourceTree = "<group>"; };
+ FB39D22E1200F35A00088E69 /* InitializeDll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeDll.cpp; sourceTree = "<group>"; };
+ FB39D22F1200F35A00088E69 /* InitializeDll.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = InitializeDll.h; sourceTree = "<group>"; };
+ FB39D2301200F35A00088E69 /* InitializeGlobals.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = InitializeGlobals.h; sourceTree = "<group>"; };
+ FB39D2311200F35A00088E69 /* InitializeParseContext.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = InitializeParseContext.h; sourceTree = "<group>"; };
+ FB39D2321200F35A00088E69 /* Intermediate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Intermediate.cpp; sourceTree = "<group>"; };
+ FB39D2331200F35A00088E69 /* intermediate.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = intermediate.h; sourceTree = "<group>"; };
+ FB39D2341200F35A00088E69 /* intermOut.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = intermOut.cpp; sourceTree = "<group>"; };
+ FB39D2351200F35A00088E69 /* IntermTraverse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IntermTraverse.cpp; sourceTree = "<group>"; };
+ FB39D2361200F35A00088E69 /* localintermediate.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = localintermediate.h; sourceTree = "<group>"; };
+ FB39D2371200F35A00088E69 /* MMap.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MMap.h; sourceTree = "<group>"; };
+ FB39D2381200F35A00088E69 /* osinclude.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osinclude.h; sourceTree = "<group>"; };
+ FB39D2391200F35A00088E69 /* ossource_posix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ossource_posix.cpp; sourceTree = "<group>"; };
+ FB39D23A1200F35A00088E69 /* ossource_win.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ossource_win.cpp; sourceTree = "<group>"; };
+ FB39D23B1200F35A00088E69 /* OutputGLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OutputGLSL.cpp; sourceTree = "<group>"; };
+ FB39D23C1200F35A00088E69 /* OutputGLSL.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = OutputGLSL.h; sourceTree = "<group>"; };
+ FB39D23F1200F35A00088E69 /* parseConst.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = parseConst.cpp; sourceTree = "<group>"; };
+ FB39D2401200F35A00088E69 /* ParseHelper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParseHelper.cpp; sourceTree = "<group>"; };
+ FB39D2411200F35A00088E69 /* ParseHelper.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = ParseHelper.h; sourceTree = "<group>"; };
+ FB39D2421200F35A00088E69 /* PoolAlloc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PoolAlloc.cpp; sourceTree = "<group>"; };
+ FB39D2431200F35A00088E69 /* PoolAlloc.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = PoolAlloc.h; sourceTree = "<group>"; };
+ FB39D2451200F35A00088E69 /* atom.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = atom.c; sourceTree = "<group>"; };
+ FB39D2461200F35A00088E69 /* atom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = atom.h; sourceTree = "<group>"; };
+ FB39D2471200F35A00088E69 /* compile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compile.h; sourceTree = "<group>"; };
+ FB39D2481200F35A00088E69 /* cpp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpp.c; sourceTree = "<group>"; };
+ FB39D2491200F35A00088E69 /* cpp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpp.h; sourceTree = "<group>"; };
+ FB39D24A1200F35A00088E69 /* cppstruct.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cppstruct.c; sourceTree = "<group>"; };
+ FB39D24B1200F35A00088E69 /* memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory.c; sourceTree = "<group>"; };
+ FB39D24C1200F35A00088E69 /* memory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = "<group>"; };
+ FB39D24D1200F35A00088E69 /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
+ FB39D24E1200F35A00088E69 /* preprocess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = preprocess.h; sourceTree = "<group>"; };
+ FB39D24F1200F35A00088E69 /* scanner.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = scanner.c; sourceTree = "<group>"; };
+ FB39D2501200F35A00088E69 /* scanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scanner.h; sourceTree = "<group>"; };
+ FB39D2511200F35A00088E69 /* slglobals.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = slglobals.h; sourceTree = "<group>"; };
+ FB39D2521200F35A00088E69 /* symbols.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = symbols.c; sourceTree = "<group>"; };
+ FB39D2531200F35A00088E69 /* symbols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = symbols.h; sourceTree = "<group>"; };
+ FB39D2541200F35A00088E69 /* tokens.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tokens.c; sourceTree = "<group>"; };
+ FB39D2551200F35A00088E69 /* tokens.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tokens.h; sourceTree = "<group>"; };
+ FB39D2561200F35A00088E69 /* QualifierAlive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = QualifierAlive.cpp; sourceTree = "<group>"; };
+ FB39D2571200F35A00088E69 /* QualifierAlive.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = QualifierAlive.h; sourceTree = "<group>"; };
+ FB39D2581200F35A00088E69 /* RemoveTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RemoveTree.cpp; sourceTree = "<group>"; };
+ FB39D2591200F35A00088E69 /* RemoveTree.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = RemoveTree.h; sourceTree = "<group>"; };
+ FB39D25A1200F35A00088E69 /* ShaderLang.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ShaderLang.cpp; sourceTree = "<group>"; };
+ FB39D25B1200F35A00088E69 /* ShHandle.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = ShHandle.h; sourceTree = "<group>"; };
+ FB39D25C1200F35A00088E69 /* SymbolTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolTable.cpp; sourceTree = "<group>"; };
+ FB39D25D1200F35A00088E69 /* SymbolTable.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = SymbolTable.h; sourceTree = "<group>"; };
+ FB39D2681200F35A00088E69 /* TranslatorGLSL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorGLSL.cpp; sourceTree = "<group>"; };
+ FB39D2691200F35A00088E69 /* TranslatorGLSL.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = TranslatorGLSL.h; sourceTree = "<group>"; };
+ FB39D26C1200F35A00088E69 /* Types.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = Types.h; sourceTree = "<group>"; };
+ FB39D26D1200F35A00088E69 /* UnfoldSelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnfoldSelect.cpp; sourceTree = "<group>"; };
+ FB39D26E1200F35A00088E69 /* UnfoldSelect.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = UnfoldSelect.h; sourceTree = "<group>"; };
+ FB39D2BF1200F3E600088E69 /* ShaderLang.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = ShaderLang.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FB39D0CF1200F0E300088E69 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 5D7C59C41208C68B001C873E /* Configurations */ = {
+ isa = PBXGroup;
+ children = (
+ 5D7C59C51208C68B001C873E /* ANGLE.xcconfig */,
+ 5D7C59C61208C68B001C873E /* Base.xcconfig */,
+ 5D7C59C71208C68B001C873E /* DebugRelease.xcconfig */,
+ );
+ path = Configurations;
+ sourceTree = "<group>";
+ };
+ FB39D06E1200ED9200088E69 = {
+ isa = PBXGroup;
+ children = (
+ FB39D2201200F35A00088E69 /* compiler */,
+ FB39D0841200EDEB00088E69 /* Source */,
+ 5D7C59C41208C68B001C873E /* Configurations */,
+ FB39D0CC1200EF9B00088E69 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ FB39D0841200EDEB00088E69 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ FB39D2BD1200F3E600088E69 /* GLSLANG */,
+ FB39D1851200F26200088E69 /* compiler */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ FB39D0CC1200EF9B00088E69 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FB39D0D11200F0E300088E69 /* libANGLE.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FB39D1851200F26200088E69 /* compiler */ = {
+ isa = PBXGroup;
+ children = (
+ FB39D1861200F26200088E69 /* BaseTypes.h */,
+ FB39D1871200F26200088E69 /* CodeGenGLSL.cpp */,
+ FB39D1881200F26200088E69 /* CodeGenHLSL.cpp */,
+ FB39D1891200F26200088E69 /* Common.h */,
+ FB39D18A1200F26200088E69 /* ConstantUnion.h */,
+ FB39D18B1200F26200088E69 /* debug.cpp */,
+ FB39D18C1200F26200088E69 /* debug.h */,
+ FB39D18F1200F26200088E69 /* InfoSink.cpp */,
+ FB39D1901200F26200088E69 /* InfoSink.h */,
+ FB39D1911200F26200088E69 /* Initialize.cpp */,
+ FB39D1921200F26200088E69 /* Initialize.h */,
+ FB39D1931200F26200088E69 /* InitializeDll.cpp */,
+ FB39D1941200F26200088E69 /* InitializeDll.h */,
+ FB39D1951200F26200088E69 /* InitializeGlobals.h */,
+ FB39D1961200F26200088E69 /* InitializeParseContext.h */,
+ FB39D1971200F26200088E69 /* Intermediate.cpp */,
+ FB39D1981200F26200088E69 /* intermediate.h */,
+ FB39D1991200F26200088E69 /* intermOut.cpp */,
+ FB39D19A1200F26200088E69 /* IntermTraverse.cpp */,
+ FB39D19B1200F26200088E69 /* localintermediate.h */,
+ FB39D19C1200F26200088E69 /* MMap.h */,
+ FB39D19D1200F26200088E69 /* osinclude.h */,
+ FB39D19E1200F26200088E69 /* ossource_posix.cpp */,
+ FB39D19F1200F26200088E69 /* ossource_win.cpp */,
+ FB39D1A01200F26200088E69 /* OutputGLSL.cpp */,
+ FB39D1A11200F26200088E69 /* OutputGLSL.h */,
+ FB39D1A21200F26200088E69 /* OutputHLSL.cpp */,
+ FB39D1A31200F26200088E69 /* OutputHLSL.h */,
+ FB39D1A41200F26200088E69 /* parseConst.cpp */,
+ FB39D1A51200F26200088E69 /* ParseHelper.cpp */,
+ FB39D1A61200F26200088E69 /* ParseHelper.h */,
+ FB39D1A71200F26200088E69 /* PoolAlloc.cpp */,
+ FB39D1A81200F26200088E69 /* PoolAlloc.h */,
+ FB39D1A91200F26200088E69 /* preprocessor */,
+ FB39D1BB1200F26200088E69 /* QualifierAlive.cpp */,
+ FB39D1BC1200F26200088E69 /* QualifierAlive.h */,
+ FB39D1BD1200F26200088E69 /* RemoveTree.cpp */,
+ FB39D1BE1200F26200088E69 /* RemoveTree.h */,
+ FB39D1BF1200F26200088E69 /* ShaderLang.cpp */,
+ FB39D1C01200F26200088E69 /* ShHandle.h */,
+ FB39D1C11200F26200088E69 /* SymbolTable.cpp */,
+ FB39D1C21200F26200088E69 /* SymbolTable.h */,
+ FB39D1CB1200F26200088E69 /* translator_common.vcproj */,
+ FB39D1CC1200F26200088E69 /* translator_hlsl.vcproj */,
+ FB39D1CD1200F26200088E69 /* TranslatorGLSL.cpp */,
+ FB39D1CE1200F26200088E69 /* TranslatorGLSL.h */,
+ FB39D1CF1200F26200088E69 /* TranslatorHLSL.cpp */,
+ FB39D1D01200F26200088E69 /* TranslatorHLSL.h */,
+ FB39D1D11200F26200088E69 /* Types.h */,
+ FB39D1D21200F26200088E69 /* UnfoldSelect.cpp */,
+ FB39D1D31200F26200088E69 /* UnfoldSelect.h */,
+ );
+ includeInIndex = 0;
+ name = compiler;
+ path = src/compiler;
+ sourceTree = "<group>";
+ };
+ FB39D1A91200F26200088E69 /* preprocessor */ = {
+ isa = PBXGroup;
+ children = (
+ FB39D1AA1200F26200088E69 /* atom.c */,
+ FB39D1AB1200F26200088E69 /* atom.h */,
+ FB39D1AC1200F26200088E69 /* compile.h */,
+ FB39D1AD1200F26200088E69 /* cpp.c */,
+ FB39D1AE1200F26200088E69 /* cpp.h */,
+ FB39D1AF1200F26200088E69 /* cppstruct.c */,
+ FB39D1B01200F26200088E69 /* memory.c */,
+ FB39D1B11200F26200088E69 /* memory.h */,
+ FB39D1B21200F26200088E69 /* parser.h */,
+ FB39D1B31200F26200088E69 /* preprocess.h */,
+ FB39D1B41200F26200088E69 /* scanner.c */,
+ FB39D1B51200F26200088E69 /* scanner.h */,
+ FB39D1B61200F26200088E69 /* slglobals.h */,
+ FB39D1B71200F26200088E69 /* symbols.c */,
+ FB39D1B81200F26200088E69 /* symbols.h */,
+ FB39D1B91200F26200088E69 /* tokens.c */,
+ FB39D1BA1200F26200088E69 /* tokens.h */,
+ );
+ includeInIndex = 0;
+ path = preprocessor;
+ sourceTree = "<group>";
+ };
+ FB39D2201200F35A00088E69 /* compiler */ = {
+ isa = PBXGroup;
+ children = (
+ A0AABE3213AFE84700F2EBD1 /* OutputGLSLBase.cpp */,
+ A0AABE3313AFE84700F2EBD1 /* OutputGLSLBase.h */,
+ A0AABE4613AFE96100F2EBD1 /* TranslatorESSL.cpp */,
+ A0AABE4713AFE96100F2EBD1 /* TranslatorESSL.h */,
+ A0AABE4213AFE94500F2EBD1 /* OutputESSL.cpp */,
+ A0AABE4313AFE94500F2EBD1 /* OutputESSL.h */,
+ A0AABE2E13AFE83000F2EBD1 /* MapLongVariableNames.cpp */,
+ A0AABE2F13AFE83000F2EBD1 /* MapLongVariableNames.h */,
+ A0AABE2A13AFE81000F2EBD1 /* ForLoopUnroll.cpp */,
+ A0AABE2B13AFE81000F2EBD1 /* ForLoopUnroll.h */,
+ FB39D2441200F35A00088E69 /* preprocessor */,
+ FB39D2211200F35A00088E69 /* BaseTypes.h */,
+ FB39D2221200F35A00088E69 /* CodeGenGLSL.cpp */,
+ FB39D2241200F35A00088E69 /* Common.h */,
+ 90D9B0F912E11DCB002D4255 /* Compiler.cpp */,
+ FB39D2251200F35A00088E69 /* ConstantUnion.h */,
+ FB39D2261200F35A00088E69 /* debug.cpp */,
+ FB39D2271200F35A00088E69 /* debug.h */,
+ 90D9B0FA12E11DCB002D4255 /* ExtensionBehavior.h */,
+ 90D9B0FB12E11DCB002D4255 /* glslang_lex.cpp */,
+ 90D9B0FC12E11DCB002D4255 /* glslang_tab.cpp */,
+ 90D9B0FD12E11DCB002D4255 /* glslang_tab.h */,
+ 90D9B0FE12E11DCB002D4255 /* glslang.h */,
+ FB39D22A1200F35A00088E69 /* InfoSink.cpp */,
+ FB39D22B1200F35A00088E69 /* InfoSink.h */,
+ FB39D22C1200F35A00088E69 /* Initialize.cpp */,
+ FB39D22D1200F35A00088E69 /* Initialize.h */,
+ FB39D22E1200F35A00088E69 /* InitializeDll.cpp */,
+ FB39D22F1200F35A00088E69 /* InitializeDll.h */,
+ FB39D2301200F35A00088E69 /* InitializeGlobals.h */,
+ FB39D2311200F35A00088E69 /* InitializeParseContext.h */,
+ FB39D2321200F35A00088E69 /* Intermediate.cpp */,
+ FB39D2331200F35A00088E69 /* intermediate.h */,
+ FB39D2341200F35A00088E69 /* intermOut.cpp */,
+ FB39D2351200F35A00088E69 /* IntermTraverse.cpp */,
+ FB39D2361200F35A00088E69 /* localintermediate.h */,
+ FB39D2371200F35A00088E69 /* MMap.h */,
+ FB39D2381200F35A00088E69 /* osinclude.h */,
+ 90D9B0FF12E11DCB002D4255 /* ossource_nspr.cpp */,
+ FB39D2391200F35A00088E69 /* ossource_posix.cpp */,
+ FB39D23A1200F35A00088E69 /* ossource_win.cpp */,
+ FB39D23B1200F35A00088E69 /* OutputGLSL.cpp */,
+ FB39D23C1200F35A00088E69 /* OutputGLSL.h */,
+ FB39D23F1200F35A00088E69 /* parseConst.cpp */,
+ FB39D2401200F35A00088E69 /* ParseHelper.cpp */,
+ FB39D2411200F35A00088E69 /* ParseHelper.h */,
+ FB39D2421200F35A00088E69 /* PoolAlloc.cpp */,
+ FB39D2431200F35A00088E69 /* PoolAlloc.h */,
+ FB39D2561200F35A00088E69 /* QualifierAlive.cpp */,
+ FB39D2571200F35A00088E69 /* QualifierAlive.h */,
+ FB39D2581200F35A00088E69 /* RemoveTree.cpp */,
+ FB39D2591200F35A00088E69 /* RemoveTree.h */,
+ 90D9B10012E11DCB002D4255 /* SearchSymbol.cpp */,
+ 90D9B10112E11DCB002D4255 /* SearchSymbol.h */,
+ FB39D25A1200F35A00088E69 /* ShaderLang.cpp */,
+ FB39D25B1200F35A00088E69 /* ShHandle.h */,
+ FB39D25C1200F35A00088E69 /* SymbolTable.cpp */,
+ FB39D25D1200F35A00088E69 /* SymbolTable.h */,
+ FB39D2681200F35A00088E69 /* TranslatorGLSL.cpp */,
+ FB39D2691200F35A00088E69 /* TranslatorGLSL.h */,
+ FB39D26C1200F35A00088E69 /* Types.h */,
+ FB39D26D1200F35A00088E69 /* UnfoldSelect.cpp */,
+ FB39D26E1200F35A00088E69 /* UnfoldSelect.h */,
+ 90D9B10B12E11DD6002D4255 /* util.cpp */,
+ 90D9B10C12E11DD6002D4255 /* util.h */,
+ 90D9B10D12E11DD6002D4255 /* ValidateLimitations.cpp */,
+ 90D9B10E12E11DD6002D4255 /* ValidateLimitations.h */,
+ 90D9B10F12E11DD6002D4255 /* VariableInfo.cpp */,
+ 90D9B11012E11DD6002D4255 /* VariableInfo.h */,
+ 90D9B11112E11DD6002D4255 /* VersionGLSL.cpp */,
+ 90D9B11212E11DD6002D4255 /* VersionGLSL.h */,
+ );
+ name = compiler;
+ path = src/compiler;
+ sourceTree = "<group>";
+ };
+ FB39D2441200F35A00088E69 /* preprocessor */ = {
+ isa = PBXGroup;
+ children = (
+ FB39D2451200F35A00088E69 /* atom.c */,
+ FB39D2461200F35A00088E69 /* atom.h */,
+ FB39D2471200F35A00088E69 /* compile.h */,
+ FB39D2481200F35A00088E69 /* cpp.c */,
+ FB39D2491200F35A00088E69 /* cpp.h */,
+ FB39D24A1200F35A00088E69 /* cppstruct.c */,
+ FB39D24B1200F35A00088E69 /* memory.c */,
+ FB39D24C1200F35A00088E69 /* memory.h */,
+ FB39D24D1200F35A00088E69 /* parser.h */,
+ FB39D24E1200F35A00088E69 /* preprocess.h */,
+ FB39D24F1200F35A00088E69 /* scanner.c */,
+ FB39D2501200F35A00088E69 /* scanner.h */,
+ FB39D2511200F35A00088E69 /* slglobals.h */,
+ FB39D2521200F35A00088E69 /* symbols.c */,
+ FB39D2531200F35A00088E69 /* symbols.h */,
+ FB39D2541200F35A00088E69 /* tokens.c */,
+ FB39D2551200F35A00088E69 /* tokens.h */,
+ );
+ path = preprocessor;
+ sourceTree = "<group>";
+ };
+ FB39D2BD1200F3E600088E69 /* GLSLANG */ = {
+ isa = PBXGroup;
+ children = (
+ FB39D2BF1200F3E600088E69 /* ShaderLang.h */,
+ );
+ name = GLSLANG;
+ path = include/GLSLANG;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ FB39D77B1201110C00088E69 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FB39D76E120110FC00088E69 /* ShaderLang.h in Headers */,
+ 90D9B10312E11DCB002D4255 /* ExtensionBehavior.h in Headers */,
+ 90D9B10612E11DCB002D4255 /* glslang_tab.h in Headers */,
+ 90D9B10712E11DCB002D4255 /* glslang.h in Headers */,
+ 90D9B10A12E11DCB002D4255 /* SearchSymbol.h in Headers */,
+ 90D9B11412E11DD6002D4255 /* util.h in Headers */,
+ 90D9B11612E11DD6002D4255 /* ValidateLimitations.h in Headers */,
+ 90D9B11812E11DD6002D4255 /* VariableInfo.h in Headers */,
+ 90D9B11A12E11DD6002D4255 /* VersionGLSL.h in Headers */,
+ A0AABE2D13AFE81000F2EBD1 /* ForLoopUnroll.h in Headers */,
+ A0AABE3113AFE83000F2EBD1 /* MapLongVariableNames.h in Headers */,
+ A0AABE3513AFE84700F2EBD1 /* OutputGLSLBase.h in Headers */,
+ A0AABE4513AFE94500F2EBD1 /* OutputESSL.h in Headers */,
+ A0AABE4913AFE96100F2EBD1 /* TranslatorESSL.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ FB39D0D01200F0E300088E69 /* ANGLE */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FB39D0D61200F11E00088E69 /* Build configuration list for PBXNativeTarget "ANGLE" */;
+ buildPhases = (
+ FB39D77B1201110C00088E69 /* Headers */,
+ FB39D0CE1200F0E300088E69 /* Sources */,
+ FB39D0CF1200F0E300088E69 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ANGLE;
+ productName = angle;
+ productReference = FB39D0D11200F0E300088E69 /* libANGLE.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FB39D0701200ED9200088E69 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0440;
+ };
+ buildConfigurationList = FB39D0731200ED9200088E69 /* Build configuration list for PBXProject "ANGLE" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = FB39D06E1200ED9200088E69;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FB39D0D01200F0E300088E69 /* ANGLE */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FB39D0CE1200F0E300088E69 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FB39D2711200F35A00088E69 /* CodeGenGLSL.cpp in Sources */,
+ FB39D2751200F35A00088E69 /* debug.cpp in Sources */,
+ FB39D2791200F35A00088E69 /* InfoSink.cpp in Sources */,
+ FB39D27B1200F35A00088E69 /* Initialize.cpp in Sources */,
+ FB39D27D1200F35A00088E69 /* InitializeDll.cpp in Sources */,
+ FB39D2811200F35A00088E69 /* Intermediate.cpp in Sources */,
+ FB39D2831200F35A00088E69 /* intermOut.cpp in Sources */,
+ FB39D2841200F35A00088E69 /* IntermTraverse.cpp in Sources */,
+ FB39D2881200F35A00088E69 /* ossource_posix.cpp in Sources */,
+ FB39D28A1200F35A00088E69 /* OutputGLSL.cpp in Sources */,
+ FB39D28E1200F35A00088E69 /* parseConst.cpp in Sources */,
+ FB39D28F1200F35A00088E69 /* ParseHelper.cpp in Sources */,
+ FB39D2911200F35A00088E69 /* PoolAlloc.cpp in Sources */,
+ FB39D2931200F35A00088E69 /* atom.c in Sources */,
+ FB39D2961200F35A00088E69 /* cpp.c in Sources */,
+ FB39D2981200F35A00088E69 /* cppstruct.c in Sources */,
+ FB39D2991200F35A00088E69 /* memory.c in Sources */,
+ FB39D29D1200F35A00088E69 /* scanner.c in Sources */,
+ FB39D2A01200F35A00088E69 /* symbols.c in Sources */,
+ FB39D2A21200F35A00088E69 /* tokens.c in Sources */,
+ FB39D2A41200F35A00088E69 /* QualifierAlive.cpp in Sources */,
+ FB39D2A61200F35A00088E69 /* RemoveTree.cpp in Sources */,
+ FB39D2A81200F35A00088E69 /* ShaderLang.cpp in Sources */,
+ FB39D2AA1200F35A00088E69 /* SymbolTable.cpp in Sources */,
+ FB39D2AC1200F35A00088E69 /* TranslatorGLSL.cpp in Sources */,
+ FB39D2B11200F35A00088E69 /* UnfoldSelect.cpp in Sources */,
+ 90D9B10212E11DCB002D4255 /* Compiler.cpp in Sources */,
+ 90D9B10412E11DCB002D4255 /* glslang_lex.cpp in Sources */,
+ 90D9B10512E11DCB002D4255 /* glslang_tab.cpp in Sources */,
+ 90D9B10912E11DCB002D4255 /* SearchSymbol.cpp in Sources */,
+ 90D9B11312E11DD6002D4255 /* util.cpp in Sources */,
+ 90D9B11512E11DD6002D4255 /* ValidateLimitations.cpp in Sources */,
+ 90D9B11712E11DD6002D4255 /* VariableInfo.cpp in Sources */,
+ 90D9B11912E11DD6002D4255 /* VersionGLSL.cpp in Sources */,
+ A0AABE2C13AFE81000F2EBD1 /* ForLoopUnroll.cpp in Sources */,
+ A0AABE3013AFE83000F2EBD1 /* MapLongVariableNames.cpp in Sources */,
+ A0AABE3413AFE84700F2EBD1 /* OutputGLSLBase.cpp in Sources */,
+ A0AABE4413AFE94500F2EBD1 /* OutputESSL.cpp in Sources */,
+ A0AABE4813AFE96100F2EBD1 /* TranslatorESSL.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 5D7C59DB1208C6C3001C873E /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5D7C59C61208C68B001C873E /* Base.xcconfig */;
+ buildSettings = {
+ };
+ name = Production;
+ };
+ 5D7C59DC1208C6C3001C873E /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5D7C59C51208C68B001C873E /* ANGLE.xcconfig */;
+ buildSettings = {
+ };
+ name = Production;
+ };
+ FB39D0711200ED9200088E69 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5D7C59C71208C68B001C873E /* DebugRelease.xcconfig */;
+ buildSettings = {
+ GCC_OPTIMIZATION_LEVEL = 0;
+ };
+ name = Debug;
+ };
+ FB39D0721200ED9200088E69 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5D7C59C71208C68B001C873E /* DebugRelease.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FB39D0D21200F0E400088E69 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5D7C59C51208C68B001C873E /* ANGLE.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ FB39D0D31200F0E400088E69 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5D7C59C51208C68B001C873E /* ANGLE.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ FB39D0731200ED9200088E69 /* Build configuration list for PBXProject "ANGLE" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FB39D0711200ED9200088E69 /* Debug */,
+ FB39D0721200ED9200088E69 /* Release */,
+ 5D7C59DB1208C6C3001C873E /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ FB39D0D61200F11E00088E69 /* Build configuration list for PBXNativeTarget "ANGLE" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FB39D0D21200F0E400088E69 /* Debug */,
+ FB39D0D31200F0E400088E69 /* Release */,
+ 5D7C59DC1208C6C3001C873E /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FB39D0701200ED9200088E69 /* Project object */;
+}
diff --git a/Source/ThirdParty/ANGLE/ChangeLog b/Source/ThirdParty/ANGLE/ChangeLog
new file mode 100644
index 000000000..ec1171579
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/ChangeLog
@@ -0,0 +1,1914 @@
+2011-11-11 Darin Adler <darin@apple.com>
+
+ * ANGLE.xcodeproj/project.pbxproj: Let a newer Xcode update this file.
+ If an older Xcode downgrades this file and we have a risk of some kind of
+ oscillating commit situation, please contact me so I know not to do this again.
+
+2011-09-19 Adam Roben <aroben@apple.com>
+
+ Let Xcode 4 do its thang with ANGLE.xcodeproj
+
+ * ANGLE.xcodeproj/project.pbxproj:
+
+2011-09-13 Anders Carlsson <andersca@apple.com>
+
+ Disable C++ exceptions when building with clang
+ https://bugs.webkit.org/show_bug.cgi?id=68031
+ <rdar://problem/9556880>
+
+ Reviewed by Mark Rowe.
+
+ * Configurations/Base.xcconfig:
+
+2011-09-08 Andras Becsi <andras.becsi@nokia.com>
+
+ [Qt] Build fails with strict compiler
+ https://bugs.webkit.org/show_bug.cgi?id=67778
+
+ Reviewed by Csaba Osztrogonác.
+
+ * src/compiler/glslang_lex.cpp: Regenerate with generate_glslang_lexer.sh using a newer flex
+ to suppress warning and fix the build when using [-Werror=unused-result]
+
+2011-08-12 Mark Rowe <mrowe@apple.com>
+
+ Be more forward-looking in the choice of compiler.
+
+ Rubber-stamped by Jon Honeycutt.
+
+ * Configurations/CompilerVersion.xcconfig:
+
+2011-08-11 Renata Hodovan <reni@webkit.org>
+
+ [Qt]Fix warnings after r92805.
+
+ Reviewed by Csaba Osztrogonác.
+
+ Control reached the end non-void functions.
+
+ * src/compiler/ossource_posix.cpp:
+ (OS_AllocTLSIndex):
+ (OS_SetTLSValue):
+
+2011-08-11 Renata Hodovan <reni@webkit.org>
+
+ Build fix on Qt Windows 32-bit Release/Debug after r92805.
+
+ Unreviewed.
+
+ * src/compiler/ossource_posix.cpp:
+ (OS_FreeTLSIndex):
+
+2011-08-04 Mark Rowe <mrowe@apple.com>
+
+ Future-proof Xcode configuration settings.
+
+ * Configurations/Base.xcconfig:
+ * Configurations/CompilerVersion.xcconfig:
+ * Configurations/DebugRelease.xcconfig:
+
+2011-06-30 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ ANGLE shouldn't try to use internal SDKs. It doesn't need them!
+
+ * Configurations/Base.xcconfig:
+
+2011-06-20 Zhenyao Mo <zmo@google.com>
+
+ Reviewed by Kenneth Russell.
+
+ Update ANGLE to r696
+ https://bugs.webkit.org/show_bug.cgi?id=56396
+
+ * ANGLE.xcodeproj/project.pbxproj:
+ * include/EGL/eglext.h:
+ * include/GLSLANG/ShaderLang.h:
+ * src/build_angle.xcodeproj/project.pbxproj:
+ * src/common/debug.cpp:
+ (gl::output):
+ (gl::trace):
+ (gl::perfActive):
+ (gl::ScopedPerfEventHelper::ScopedPerfEventHelper):
+ (gl::ScopedPerfEventHelper::~ScopedPerfEventHelper):
+ * src/common/debug.h:
+ * src/common/version.h: Added.
+ * src/compiler/CodeGenGLSL.cpp:
+ (ConstructCompiler):
+ * src/compiler/CodeGenHLSL.cpp:
+ (ConstructCompiler):
+ * src/compiler/Compiler.cpp:
+ (TCompiler::compile):
+ (TCompiler::mapLongVariableNames):
+ (TCompiler::getMappedNameMaxLength):
+ (TCompiler::getExtensionBehavior):
+ * src/compiler/ConstantUnion.h:
+ (ConstantUnion::operator==):
+ (ConstantUnion::operator>):
+ (ConstantUnion::operator<):
+ * src/compiler/ExtensionBehavior.h:
+ (getBehaviorString):
+ * src/compiler/ForLoopUnroll.cpp: Added.
+ (ForLoopUnroll::FillLoopIndexInfo):
+ (ForLoopUnroll::Step):
+ (ForLoopUnroll::SatisfiesLoopCondition):
+ (ForLoopUnroll::NeedsToReplaceSymbolWithValue):
+ (ForLoopUnroll::GetLoopIndexValue):
+ (ForLoopUnroll::Push):
+ (ForLoopUnroll::Pop):
+ (ForLoopUnroll::getLoopIncrement):
+ (ForLoopUnroll::evaluateIntConstant):
+ * src/compiler/ForLoopUnroll.h: Added.
+ (ForLoopUnroll::ForLoopUnroll):
+ * src/compiler/Initialize.cpp:
+ (BuiltInFunctionsVertex):
+ * src/compiler/MapLongVariableNames.cpp: Added.
+ (MapLongVariableNames::MapLongVariableNames):
+ (MapLongVariableNames::visitSymbol):
+ (MapLongVariableNames::visitConstantUnion):
+ (MapLongVariableNames::visitBinary):
+ (MapLongVariableNames::visitUnary):
+ (MapLongVariableNames::visitSelection):
+ (MapLongVariableNames::visitAggregate):
+ (MapLongVariableNames::visitLoop):
+ (MapLongVariableNames::visitBranch):
+ (MapLongVariableNames::mapVaryingLongName):
+ * src/compiler/MapLongVariableNames.h: Added.
+ * src/compiler/OutputESSL.cpp: Added.
+ (TOutputESSL::TOutputESSL):
+ (TOutputESSL::writeVariablePrecision):
+ * src/compiler/OutputESSL.h: Added.
+ * src/compiler/OutputGLSL.cpp:
+ (TOutputGLSL::TOutputGLSL):
+ (TOutputGLSL::writeVariablePrecision):
+ * src/compiler/OutputGLSL.h:
+ * src/compiler/OutputGLSLBase.cpp: Added.
+ (TOutputGLSLBase::TOutputGLSLBase):
+ (TOutputGLSLBase::writeTriplet):
+ (TOutputGLSLBase::writeVariableType):
+ (TOutputGLSLBase::writeFunctionParameters):
+ (TOutputGLSLBase::writeConstantUnion):
+ (TOutputGLSLBase::visitSymbol):
+ (TOutputGLSLBase::visitConstantUnion):
+ (TOutputGLSLBase::visitBinary):
+ (TOutputGLSLBase::visitUnary):
+ (TOutputGLSLBase::visitSelection):
+ (TOutputGLSLBase::visitAggregate):
+ (TOutputGLSLBase::visitLoop):
+ (TOutputGLSLBase::visitBranch):
+ (TOutputGLSLBase::visitCodeBlock):
+ * src/compiler/OutputGLSLBase.h: Added.
+ (TOutputGLSLBase::objSink):
+ * src/compiler/OutputHLSL.cpp:
+ (sh::OutputHLSL::OutputHLSL):
+ (sh::OutputHLSL::header):
+ (sh::OutputHLSL::visitUnary):
+ (sh::OutputHLSL::visitAggregate):
+ (sh::OutputHLSL::visitSelection):
+ (sh::OutputHLSL::visitLoop):
+ (sh::OutputHLSL::visitBranch):
+ (sh::OutputHLSL::handleExcessiveLoop):
+ (sh::OutputHLSL::outputLineDirective):
+ * src/compiler/OutputHLSL.h:
+ * src/compiler/ParseHelper.cpp:
+ (TParseContext::precisionErrorCheck):
+ (TParseContext::constructorErrorCheck):
+ (TParseContext::nonInitErrorCheck):
+ * src/compiler/ParseHelper.h:
+ (TParseContext::TParseContext):
+ * src/compiler/ShHandle.h:
+ * src/compiler/ShaderLang.cpp:
+ (getVariableInfo):
+ (ShConstructCompiler):
+ (ShGetInfo):
+ (ShGetActiveAttrib):
+ (ShGetActiveUniform):
+ * src/compiler/TranslatorESSL.cpp: Added.
+ (TranslatorESSL::TranslatorESSL):
+ (TranslatorESSL::translate):
+ (TranslatorESSL::writeExtensionBehavior):
+ * src/compiler/TranslatorESSL.h: Added.
+ * src/compiler/ValidateLimitations.cpp:
+ (ValidateLimitations::visitBinary):
+ (ValidateLimitations::visitLoop):
+ * src/compiler/ValidateLimitations.h:
+ * src/compiler/VariableInfo.cpp:
+ (getVariableInfo):
+ (getBuiltInVariableInfo):
+ (getUserDefinedVariableInfo):
+ (CollectAttribsUniforms::visitAggregate):
+ * src/compiler/VariableInfo.h:
+ * src/compiler/VersionGLSL.cpp:
+ (TVersionGLSL::visitSymbol):
+ (TVersionGLSL::visitConstantUnion):
+ (TVersionGLSL::visitBinary):
+ (TVersionGLSL::visitUnary):
+ (TVersionGLSL::visitSelection):
+ (TVersionGLSL::visitAggregate):
+ (TVersionGLSL::visitLoop):
+ (TVersionGLSL::visitBranch):
+ * src/compiler/VersionGLSL.h:
+ * src/compiler/glslang.y:
+ * src/compiler/glslang_tab.cpp:
+ * src/compiler/glslang_tab.h:
+ * src/compiler/intermediate.h:
+ (TIntermLoop::TIntermLoop):
+ (TIntermLoop::setUnrollFlag):
+ (TIntermLoop::getUnrollFlag):
+ (TIntermSymbol::TIntermSymbol):
+ (TIntermSymbol::setId):
+ (TIntermSymbol::setSymbol):
+ (TIntermSymbol::getOriginalSymbol):
+ (TIntermAggregate::TIntermAggregate):
+ (TIntermAggregate::setEndLine):
+ (TIntermAggregate::getEndLine):
+ * src/compiler/preprocessor/atom.c:
+ (AddString):
+ * src/compiler/preprocessor/compile.h:
+ * src/compiler/preprocessor/cpp.c:
+ (CPPelse):
+ (eval):
+ (CPPif):
+ (CPPifdef):
+ (readCPPline):
+ (ChkCorrectElseNesting):
+ * src/compiler/preprocessor/cppstruct.c:
+ (ResetPreprocessor):
+ * src/compiler/preprocessor/scanner.c:
+ (byte_scan):
+ (yylex_CPP):
+ * src/compiler/preprocessor/scanner.h:
+ * src/libEGL/Config.cpp:
+ (egl::Config::Config):
+ (egl::Config::set):
+ (egl::ConfigSet::add):
+ (egl::ConfigSet::getConfigs):
+ * src/libEGL/Config.h:
+ * src/libEGL/Display.cpp:
+ (egl::Display::Display):
+ (egl::Display::initialize):
+ (egl::Display::terminate):
+ (egl::Display::getConfigAttrib):
+ (egl::Display::createDevice):
+ (egl::Display::createWindowSurface):
+ (egl::Display::createOffscreenSurface):
+ (egl::Display::createContext):
+ (egl::Display::destroyContext):
+ (egl::Display::isInitialized):
+ (egl::Display::getAdapterIdentifier):
+ (egl::Display::isDeviceLost):
+ (egl::Display::getBufferPool):
+ (egl::Display::initExtensionString):
+ (egl::Display::getExtensionString):
+ (egl::Display::getVertexTextureSupport):
+ (egl::Display::getNonPower2TextureSupport):
+ * src/libEGL/Display.h:
+ (egl::Display::isD3d9ExDevice):
+ * src/libEGL/Surface.cpp:
+ (egl::Surface::Surface):
+ (egl::Surface::initialize):
+ (egl::Surface::release):
+ (egl::Surface::resetSwapChain):
+ (egl::SurfaceWindowProc):
+ (egl::Surface::subclassWindow):
+ (egl::Surface::unsubclassWindow):
+ (egl::Surface::swap):
+ (egl::Surface::getRenderTarget):
+ (egl::Surface::getOffscreenTexture):
+ (egl::Surface::getTextureFormat):
+ (egl::Surface::getTextureTarget):
+ (egl::Surface::setBoundTexture):
+ (egl::Surface::getBoundTexture):
+ (egl::Surface::getFormat):
+ * src/libEGL/Surface.h:
+ (egl::Surface::getShareHandle):
+ * src/libEGL/libEGL.cpp:
+ (validateDisplay):
+ (validateConfig):
+ (validateContext):
+ (validateSurface):
+ * src/libEGL/libEGL.rc: Added.
+ * src/libEGL/libEGL.vcproj:
+ * src/libEGL/main.cpp:
+ (DllMain):
+ * src/libEGL/main.h:
+ * src/libEGL/resource.h: Added.
+ * src/libGLESv2/Blit.cpp:
+ (gl::Blit::initGeometry):
+ (gl::Blit::copy):
+ * src/libGLESv2/Blit.h:
+ * src/libGLESv2/Buffer.cpp:
+ (gl::Buffer::Buffer):
+ (gl::Buffer::~Buffer):
+ (gl::Buffer::bufferData):
+ (gl::Buffer::bufferSubData):
+ (gl::Buffer::getStaticVertexBuffer):
+ (gl::Buffer::getStaticIndexBuffer):
+ (gl::Buffer::invalidateStaticData):
+ (gl::Buffer::promoteStaticUsage):
+ * src/libGLESv2/Buffer.h:
+ * src/libGLESv2/Context.cpp:
+ (gl::Context::Context):
+ (gl::Context::~Context):
+ (gl::Context::makeCurrent):
+ (gl::Context::markAllStateDirty):
+ (gl::Context::setActiveSampler):
+ (gl::Context::createFramebuffer):
+ (gl::Context::createFence):
+ (gl::Context::deleteFramebuffer):
+ (gl::Context::deleteFence):
+ (gl::Context::bindTexture2D):
+ (gl::Context::bindTextureCubeMap):
+ (gl::Context::getTexture2D):
+ (gl::Context::getTextureCubeMap):
+ (gl::Context::getSamplerTexture):
+ (gl::Context::getIntegerv):
+ (gl::Context::applyRenderTarget):
+ (gl::Context::applyState):
+ (gl::Context::applyVertexBuffer):
+ (gl::Context::applyShaders):
+ (gl::Context::applyTextures):
+ (gl::Context::readPixels):
+ (gl::Context::clear):
+ (gl::Context::drawArrays):
+ (gl::Context::drawElements):
+ (gl::Context::finish):
+ (gl::Context::flush):
+ (gl::Context::drawClosingLine):
+ (gl::Context::getMaximumVertexTextureImageUnits):
+ (gl::Context::getMaximumCombinedTextureImageUnits):
+ (gl::Context::supportsNonPower2Texture):
+ (gl::Context::detachTexture):
+ (gl::Context::getIncompleteTexture):
+ (gl::Context::initExtensionString):
+ (gl::Context::blitFramebuffer):
+ (gl::VertexDeclarationCache::VertexDeclarationCache):
+ (gl::VertexDeclarationCache::~VertexDeclarationCache):
+ (gl::VertexDeclarationCache::applyDeclaration):
+ * src/libGLESv2/Context.h:
+ * src/libGLESv2/Framebuffer.cpp:
+ (gl::Framebuffer::lookupRenderbuffer):
+ (gl::Framebuffer::completeness):
+ * src/libGLESv2/Framebuffer.h:
+ * src/libGLESv2/HandleAllocator.cpp: Added.
+ (gl::HandleAllocator::HandleAllocator):
+ (gl::HandleAllocator::~HandleAllocator):
+ (gl::HandleAllocator::setBaseHandle):
+ (gl::HandleAllocator::allocate):
+ (gl::HandleAllocator::release):
+ * src/libGLESv2/HandleAllocator.h: Added.
+ * src/libGLESv2/IndexDataManager.cpp: Added.
+ (gl::IndexDataManager::IndexDataManager):
+ (gl::IndexDataManager::~IndexDataManager):
+ (gl::convertIndices):
+ (gl::computeRange):
+ (gl::IndexDataManager::prepareIndexData):
+ (gl::IndexDataManager::indexSize):
+ (gl::IndexDataManager::typeSize):
+ (gl::IndexBuffer::IndexBuffer):
+ (gl::IndexBuffer::~IndexBuffer):
+ (gl::IndexBuffer::getBuffer):
+ (gl::IndexBuffer::unmap):
+ (gl::StreamingIndexBuffer::StreamingIndexBuffer):
+ (gl::StreamingIndexBuffer::~StreamingIndexBuffer):
+ (gl::StreamingIndexBuffer::map):
+ (gl::StreamingIndexBuffer::reserveSpace):
+ (gl::StaticIndexBuffer::StaticIndexBuffer):
+ (gl::StaticIndexBuffer::~StaticIndexBuffer):
+ (gl::StaticIndexBuffer::map):
+ (gl::StaticIndexBuffer::reserveSpace):
+ (gl::StaticIndexBuffer::lookupType):
+ (gl::StaticIndexBuffer::lookupRange):
+ (gl::StaticIndexBuffer::addRange):
+ * src/libGLESv2/IndexDataManager.h: Added.
+ (gl::IndexBuffer::size):
+ * src/libGLESv2/Program.cpp:
+ (gl::Program::getSemanticIndex):
+ (gl::Program::getSamplerMapping):
+ (gl::Program::getSamplerTextureType):
+ (gl::Program::compileToBinary):
+ (gl::Program::packVaryings):
+ (gl::Program::linkVaryings):
+ (gl::Program::link):
+ (gl::Program::linkUniforms):
+ (gl::Program::defineUniform):
+ (gl::Program::applyUniform1iv):
+ (gl::Program::appendToInfoLogSanitized):
+ (gl::Program::unlink):
+ (gl::Program::getActiveUniformMaxLength):
+ (gl::Program::validate):
+ (gl::Program::validateSamplers):
+ * src/libGLESv2/Program.h:
+ * src/libGLESv2/Renderbuffer.cpp:
+ (gl::Renderbuffer::getWidth):
+ (gl::Renderbuffer::getHeight):
+ (gl::Renderbuffer::getInternalFormat):
+ (gl::Renderbuffer::getRedSize):
+ (gl::Renderbuffer::getGreenSize):
+ (gl::Renderbuffer::getBlueSize):
+ (gl::Renderbuffer::getAlphaSize):
+ (gl::Renderbuffer::getDepthSize):
+ (gl::Renderbuffer::getStencilSize):
+ (gl::Renderbuffer::getSamples):
+ (gl::RenderbufferStorage::RenderbufferStorage):
+ (gl::RenderbufferStorage::getWidth):
+ (gl::RenderbufferStorage::getHeight):
+ (gl::RenderbufferStorage::getInternalFormat):
+ (gl::RenderbufferStorage::getRedSize):
+ (gl::RenderbufferStorage::getGreenSize):
+ (gl::RenderbufferStorage::getBlueSize):
+ (gl::RenderbufferStorage::getAlphaSize):
+ (gl::RenderbufferStorage::getDepthSize):
+ (gl::RenderbufferStorage::getStencilSize):
+ (gl::RenderbufferStorage::getD3DFormat):
+ (gl::Colorbuffer::Colorbuffer):
+ (gl::Colorbuffer::getWidth):
+ (gl::Colorbuffer::getHeight):
+ (gl::Colorbuffer::getInternalFormat):
+ (gl::Colorbuffer::getType):
+ (gl::Colorbuffer::getD3DFormat):
+ (gl::Colorbuffer::isColorbuffer):
+ (gl::Colorbuffer::getRenderTarget):
+ (gl::DepthStencilbuffer::DepthStencilbuffer):
+ (gl::Depthbuffer::Depthbuffer):
+ (gl::Stencilbuffer::Stencilbuffer):
+ * src/libGLESv2/Renderbuffer.h:
+ * src/libGLESv2/ResourceManager.cpp:
+ (gl::ResourceManager::createBuffer):
+ (gl::ResourceManager::createShader):
+ (gl::ResourceManager::createProgram):
+ (gl::ResourceManager::createTexture):
+ (gl::ResourceManager::createRenderbuffer):
+ (gl::ResourceManager::deleteBuffer):
+ (gl::ResourceManager::deleteShader):
+ (gl::ResourceManager::deleteProgram):
+ (gl::ResourceManager::deleteTexture):
+ (gl::ResourceManager::deleteRenderbuffer):
+ (gl::ResourceManager::checkTextureAllocation):
+ * src/libGLESv2/ResourceManager.h:
+ * src/libGLESv2/Shader.cpp:
+ (gl::Shader::Shader):
+ (gl::Shader::compileToHLSL):
+ * src/libGLESv2/Shader.h:
+ * src/libGLESv2/Texture.cpp:
+ (gl::Texture::Image::Image):
+ (gl::Texture::Image::~Image):
+ (gl::Texture::Image::isRenderable):
+ (gl::Texture::Image::getD3DFormat):
+ (gl::Texture::Texture):
+ (gl::Texture::setMinFilter):
+ (gl::Texture::setMagFilter):
+ (gl::Texture::setWrapS):
+ (gl::Texture::setWrapT):
+ (gl::Texture::loadImageData):
+ (gl::Texture::loadAlphaImageData):
+ (gl::Texture::loadAlphaFloatImageData):
+ (gl::Texture::loadAlphaHalfFloatImageData):
+ (gl::Texture::loadLuminanceImageData):
+ (gl::Texture::loadLuminanceFloatImageData):
+ (gl::Texture::loadLuminanceHalfFloatImageData):
+ (gl::Texture::loadLuminanceAlphaImageData):
+ (gl::Texture::loadLuminanceAlphaFloatImageData):
+ (gl::Texture::loadLuminanceAlphaHalfFloatImageData):
+ (gl::Texture::loadRGBUByteImageData):
+ (gl::Texture::loadRGB565ImageData):
+ (gl::Texture::loadRGBFloatImageData):
+ (gl::Texture::loadRGBHalfFloatImageData):
+ (gl::Texture::loadRGBAUByteImageDataSSE2):
+ (gl::Texture::loadRGBAUByteImageData):
+ (gl::Texture::loadRGBA4444ImageData):
+ (gl::Texture::loadRGBA5551ImageData):
+ (gl::Texture::loadRGBAFloatImageData):
+ (gl::Texture::loadRGBAHalfFloatImageData):
+ (gl::Texture::loadBGRAImageData):
+ (gl::Texture::loadCompressedImageData):
+ (gl::Texture::createSurface):
+ (gl::Texture::setImage):
+ (gl::Texture::setCompressedImage):
+ (gl::Texture::subImage):
+ (gl::Texture::subImageCompressed):
+ (gl::Texture::copyToImage):
+ (gl::Texture::getTexture):
+ (gl::Texture::isDirtyParameter):
+ (gl::Texture::isDirtyImage):
+ (gl::Texture::resetDirty):
+ (gl::Texture::getSerial):
+ (gl::Texture::creationLevels):
+ (gl::Texture::levelCount):
+ (gl::Texture::issueSerial):
+ (gl::Texture2D::Texture2D):
+ (gl::Texture2D::~Texture2D):
+ (gl::Texture2D::getWidth):
+ (gl::Texture2D::getHeight):
+ (gl::Texture2D::getInternalFormat):
+ (gl::Texture2D::getType):
+ (gl::Texture2D::getD3DFormat):
+ (gl::Texture2D::redefineTexture):
+ (gl::Texture2D::setImage):
+ (gl::Texture2D::bindTexImage):
+ (gl::Texture2D::releaseTexImage):
+ (gl::Texture2D::setCompressedImage):
+ (gl::Texture2D::commitRect):
+ (gl::Texture2D::copyImage):
+ (gl::Texture2D::copySubImage):
+ (gl::Texture2D::isComplete):
+ (gl::Texture2D::isCompressed):
+ (gl::Texture2D::getBaseTexture):
+ (gl::Texture2D::createTexture):
+ (gl::Texture2D::updateTexture):
+ (gl::Texture2D::convertToRenderTarget):
+ (gl::Texture2D::generateMipmaps):
+ (gl::Texture2D::getRenderbuffer):
+ (gl::Texture2D::getRenderTarget):
+ (gl::TextureCubeMap::getWidth):
+ (gl::TextureCubeMap::getHeight):
+ (gl::TextureCubeMap::getInternalFormat):
+ (gl::TextureCubeMap::getType):
+ (gl::TextureCubeMap::getD3DFormat):
+ (gl::TextureCubeMap::setImagePosX):
+ (gl::TextureCubeMap::setImageNegX):
+ (gl::TextureCubeMap::setImagePosY):
+ (gl::TextureCubeMap::setImageNegY):
+ (gl::TextureCubeMap::setImagePosZ):
+ (gl::TextureCubeMap::setImageNegZ):
+ (gl::TextureCubeMap::setCompressedImage):
+ (gl::TextureCubeMap::commitRect):
+ (gl::TextureCubeMap::isComplete):
+ (gl::TextureCubeMap::isCompressed):
+ (gl::TextureCubeMap::getBaseTexture):
+ (gl::TextureCubeMap::createTexture):
+ (gl::TextureCubeMap::updateTexture):
+ (gl::TextureCubeMap::convertToRenderTarget):
+ (gl::TextureCubeMap::setImage):
+ (gl::TextureCubeMap::redefineTexture):
+ (gl::TextureCubeMap::copyImage):
+ (gl::TextureCubeMap::getCubeMapSurface):
+ (gl::TextureCubeMap::copySubImage):
+ (gl::TextureCubeMap::generateMipmaps):
+ (gl::TextureCubeMap::getRenderbuffer):
+ (gl::TextureCubeMap::getRenderTarget):
+ * src/libGLESv2/Texture.h:
+ * src/libGLESv2/VertexDataManager.cpp: Added.
+ (gl::VertexDataManager::VertexDataManager):
+ (gl::VertexDataManager::~VertexDataManager):
+ (gl::VertexDataManager::writeAttributeData):
+ (gl::VertexDataManager::prepareVertexData):
+ (gl::VertexDataManager::spaceRequired):
+ (gl::VertexDataManager::checkVertexCaps):
+ (gl::VertexDataManager::typeIndex):
+ (gl::VertexBuffer::VertexBuffer):
+ (gl::VertexBuffer::~VertexBuffer):
+ (gl::VertexBuffer::unmap):
+ (gl::VertexBuffer::getBuffer):
+ (gl::ConstantVertexBuffer::ConstantVertexBuffer):
+ (gl::ConstantVertexBuffer::~ConstantVertexBuffer):
+ (gl::ArrayVertexBuffer::ArrayVertexBuffer):
+ (gl::ArrayVertexBuffer::~ArrayVertexBuffer):
+ (gl::ArrayVertexBuffer::addRequiredSpace):
+ (gl::ArrayVertexBuffer::addRequiredSpaceFor):
+ (gl::StreamingVertexBuffer::StreamingVertexBuffer):
+ (gl::StreamingVertexBuffer::~StreamingVertexBuffer):
+ (gl::StreamingVertexBuffer::map):
+ (gl::StreamingVertexBuffer::reserveRequiredSpace):
+ (gl::StaticVertexBuffer::StaticVertexBuffer):
+ (gl::StaticVertexBuffer::~StaticVertexBuffer):
+ (gl::StaticVertexBuffer::map):
+ (gl::StaticVertexBuffer::reserveRequiredSpace):
+ (gl::StaticVertexBuffer::lookupAttribute):
+ (gl::VertexDataManager::formatConverter):
+ * src/libGLESv2/VertexDataManager.h: Added.
+ (gl::ArrayVertexBuffer::size):
+ (gl::VertexDataManager::dirtyCurrentValue):
+ * src/libGLESv2/libGLESv2.cpp:
+ (validImageSize):
+ (Extension::glBindTexImage):
+ * src/libGLESv2/libGLESv2.def:
+ * src/libGLESv2/libGLESv2.rc: Added.
+ * src/libGLESv2/libGLESv2.vcproj:
+ * src/libGLESv2/main.cpp:
+ (error):
+ * src/libGLESv2/mathutil.h:
+ (gl::clamp):
+ (gl::clamp01):
+ (gl::transformPixelRect):
+ (gl::transformPixelYOffset):
+ (gl::adjustWinding):
+ (gl::supportsSSE2):
+ * src/libGLESv2/resource.h: Added.
+ * src/libGLESv2/utilities.cpp:
+ (gl::ComputeCompressedPitch):
+ (es2dx::ConvertCubeFace):
+ (es2dx::ConvertPrimitiveType):
+ (es2dx::ConvertRenderbufferFormat):
+ (es2dx::GetMultisampleTypeFromSamples):
+ (dx2es::GetStencilSize):
+ (dx2es::GetAlphaSize):
+ (dx2es::GetRedSize):
+ (dx2es::GetGreenSize):
+ (dx2es::GetBlueSize):
+ (dx2es::GetDepthSize):
+ (getTempPath):
+ (writeFile):
+ * src/libGLESv2/utilities.h:
+ * src/libGLESv2/vertexconversion.h: Added.
+ (gl::Identity::convert):
+ (gl::Cast::convert):
+ (gl::Normalize::convert):
+ (gl::FixedToFloat::convert):
+ (gl::SimpleDefaultValues::zero):
+ (gl::SimpleDefaultValues::one):
+ (gl::NormalizedDefaultValues::zero):
+ (gl::NormalizedDefaultValues::one):
+ (gl::VertexDataConverter::convertArray):
+ (gl::VertexDataConverter::pointerAddBytes):
+ (gl::VertexDataConverter::copyComponent):
+
+2011-05-24 David Kilzer <ddkilzer@apple.com>
+
+ Part 2 of 2: <http://webkit.org/b/60805> Enable -Wnewline-eof on ANGLE
+
+ Reviewed by Adam Roben.
+
+ * Configurations/Base.xcconfig:
+ (GCC_WARN_ABOUT_MISSING_NEWLINE): Added. Set to YES.
+
+2011-05-23 David Kilzer <ddkilzer@apple.com>
+
+ Part 1 of 2: <http://webkit.org/b/60805> Enable -Wnewline-eof on ANGLE
+
+ Merge ANGLE upstream commit r653 for Issue 154.
+
+ * src/compiler/PoolAlloc.h: Added newline to end of file.
+ * src/compiler/ShHandle.h: Ditto.
+ * src/libEGL/Display.cpp: Ditto.
+
+2011-05-16 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/60913> C++ exceptions should not be enabled when building with llvm-gcc-4.2
+ <rdar://problem/9446430>
+
+ Reviewed by Mark Rowe.
+
+ * Configurations/Base.xcconfig: Fixed typo.
+
+2011-05-04 David Kilzer <ddkilzer@apple.com>
+
+ Part 2 of 2: <http://webkit.org/b/56337> Enable -Werror on ANGLE
+
+ Reviewed by Adam Barth.
+
+ * Configurations/Base.xcconfig:
+ (GCC_TREAT_WARNINGS_AS_ERRORS): Set to YES.
+
+2011-05-04 David Kilzer <ddkilzer@apple.com>
+
+ Part 1 of 2: <http://webkit.org/b/56337> Enable -Werror on ANGLE
+
+ Merge ANGLE upstream commits r572, r573, r574, r575.
+
+ This unblocks enabling -Werror on ANGLE. Since all changes are
+ in the upstream repository, they may be safely overwritten
+ during the next ANGLE update.
+
+ * src/compiler/ConstantUnion.h:
+ (ConstantUnion::operator==): Added a default case.
+ * src/compiler/Intermediate.cpp:
+ (TIntermBinary::promote): Added parentheses.
+ * src/compiler/ParseHelper.cpp:
+ (TParseContext::precisionErrorCheck): Added a default case.
+ * src/compiler/PoolAlloc.cpp:
+ (TAllocation::checkGuardBlock): Changed '%u' to '%lu' for size_t
+ variable. Put for loop inside #ifdef GUARD_BLOCKS/#endif macros
+ to fix tautological-compare warning.
+ (TAllocation::checkAllocList): Added newline to end of file.
+
+2011-04-26 Dan Bernstein <mitz@apple.com>
+
+ Build fix.
+
+ * Configurations/CompilerVersion.xcconfig:
+
+2011-04-26 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Choose the compiler based on the Xcode version for Snow Leopard debug builds.
+
+ * Configurations/Base.xcconfig:
+ * Configurations/CompilerVersion.xcconfig: Added.
+
+2011-03-17 Jeff Miller <jeffm@apple.com>
+
+ Use a consistent set of file patterns in the svn:ignore property for all .xcodeproj directories, specifically:
+
+ *.mode*
+ *.pbxuser
+ *.perspective*
+ project.xcworkspace
+ xcuserdata
+
+ * ANGLE.xcodeproj: Modified property svn:ignore.
+ * src/build_angle.xcodeproj: Modified property svn:ignore.
+
+2011-01-18 Kenneth Russell <kbr@google.com>
+
+ Unreviewed, Leopard build fix. Remove flex/bison targets for GLSL
+ grammar because the generated sources are already checked in.
+
+ * ANGLE.xcodeproj/project.pbxproj:
+ * src/build_angle.xcodeproj/project.pbxproj:
+
+2011-01-18 Kenneth Russell <kbr@google.com>
+
+ Unreviewed, release build fix. Explicitly cast away const.
+
+ * src/compiler/preprocessor/scanner.c:
+ (ScanFromString):
+
+2011-01-18 Ben Vanik <ben.vanik@gmail.com>
+
+ Reviewed by Kenneth Russell.
+
+ Updating ANGLE in WebKit to r533.
+ https://bugs.webkit.org/show_bug.cgi?id=47194
+
+ * ANGLE.xcodeproj/project.pbxproj:
+ * include/GLSLANG/ShaderLang.h:
+ * src/common/debug.cpp:
+ (gl::trace):
+ * src/common/debug.h:
+ * src/compiler/CodeGenGLSL.cpp:
+ (ConstructCompiler):
+ * src/compiler/CodeGenHLSL.cpp:
+ (ConstructCompiler):
+ * src/compiler/Common.h:
+ (EncodeSourceLoc):
+ (DecodeSourceLoc):
+ * src/compiler/Compiler.cpp: Added.
+ (TShHandleBase::TShHandleBase):
+ (TShHandleBase::~TShHandleBase):
+ (TCompiler::TCompiler):
+ (TCompiler::~TCompiler):
+ (TCompiler::Init):
+ (TCompiler::compile):
+ (TCompiler::InitBuiltInSymbolTable):
+ (TCompiler::clearResults):
+ (TCompiler::validateLimitations):
+ (TCompiler::collectAttribsUniforms):
+ * src/compiler/ExtensionBehavior.h: Added.
+ * src/compiler/InfoSink.cpp:
+ (TInfoSinkBase::location):
+ * src/compiler/InfoSink.h:
+ (TInfoSinkBase::size):
+ * src/compiler/Initialize.cpp:
+ (BuiltInFunctionsCommon):
+ (BuiltInFunctionsVertex):
+ (BuiltInFunctionsFragment):
+ (StandardUniforms):
+ (DefaultPrecisionVertex):
+ (DefaultPrecisionFragment):
+ (BuiltInConstants):
+ (TBuiltIns::initialize):
+ (IdentifyBuiltIns):
+ (InitExtensionBehavior):
+ * src/compiler/Initialize.h:
+ * src/compiler/IntermTraverse.cpp:
+ (TIntermLoop::traverse):
+ * src/compiler/Intermediate.cpp:
+ (getOperatorString):
+ (TIntermediate::addBinaryMath):
+ (TIntermediate::addLoop):
+ (TIntermediate::postProcess):
+ (TIntermBinary::promote):
+ * src/compiler/OutputGLSL.cpp:
+ (TOutputGLSL::visitUnary):
+ (TOutputGLSL::visitLoop):
+ * src/compiler/OutputHLSL.cpp:
+ (sh::OutputHLSL::OutputHLSL):
+ (sh::OutputHLSL::header):
+ (sh::OutputHLSL::visitBinary):
+ (sh::OutputHLSL::visitUnary):
+ (sh::OutputHLSL::visitAggregate):
+ (sh::OutputHLSL::visitLoop):
+ (sh::OutputHLSL::handleExcessiveLoop):
+ (sh::OutputHLSL::argumentString):
+ * src/compiler/OutputHLSL.h:
+ * src/compiler/ParseHelper.cpp:
+ (ReportInfo):
+ (DefineExtensionMacros):
+ (TParseContext::error):
+ (TParseContext::warning):
+ (TParseContext::reservedErrorCheck):
+ (TParseContext::constructorErrorCheck):
+ (TParseContext::arrayQualifierErrorCheck):
+ (TParseContext::extensionErrorCheck):
+ (TParseContext::areAllChildConst):
+ (PaParseStrings):
+ * src/compiler/ParseHelper.h:
+ (TParseContext::TParseContext):
+ * src/compiler/PoolAlloc.cpp:
+ (InitializeGlobalPools):
+ (FreeGlobalPools):
+ (SetGlobalPoolAllocator):
+ (TPoolAllocator::TPoolAllocator):
+ (TPoolAllocator::~TPoolAllocator):
+ (TAllocation::checkAllocList):
+ * src/compiler/PoolAlloc.h:
+ * src/compiler/SearchSymbol.cpp: Added.
+ (sh::SearchSymbol::SearchSymbol):
+ (sh::SearchSymbol::traverse):
+ (sh::SearchSymbol::visitSymbol):
+ (sh::SearchSymbol::foundMatch):
+ * src/compiler/SearchSymbol.h: Added.
+ * src/compiler/ShHandle.h:
+ (TCompiler::getAsCompiler):
+ (TCompiler::getInfoSink):
+ (TCompiler::getAttribs):
+ (TCompiler::getUniforms):
+ (TCompiler::getShaderType):
+ (TCompiler::getShaderSpec):
+ * src/compiler/ShaderLang.cpp:
+ (getVariableMaxLength):
+ (getVariableInfo):
+ (ShInitBuiltInResources):
+ (ShConstructCompiler):
+ (ShCompile):
+ (ShGetInfo):
+ (ShGetInfoLog):
+ (ShGetObjectCode):
+ (ShGetActiveAttrib):
+ (ShGetActiveUniform):
+ * src/compiler/SymbolTable.cpp:
+ (TSymbolTableLevel::relateToExtension):
+ * src/compiler/SymbolTable.h:
+ (TVariable::shareConstPointer):
+ (TFunction::relateToExtension):
+ (TFunction::getExtension):
+ (TFunction::getParamCount):
+ (TFunction::getParam):
+ (TSymbolTable::getGlobalLevel):
+ (TSymbolTable::relateToOperator):
+ (TSymbolTable::relateToExtension):
+ * src/compiler/TranslatorGLSL.cpp:
+ (writeVersion):
+ (TranslatorGLSL::TranslatorGLSL):
+ (TranslatorGLSL::translate):
+ * src/compiler/TranslatorGLSL.h:
+ * src/compiler/TranslatorHLSL.cpp:
+ (TranslatorHLSL::TranslatorHLSL):
+ (TranslatorHLSL::translate):
+ * src/compiler/TranslatorHLSL.h:
+ * src/compiler/Types.h:
+ (TType::TType):
+ * src/compiler/UnfoldSelect.cpp:
+ (sh::UnfoldSelect::visitSelection):
+ * src/compiler/UnfoldSelect.h:
+ * src/compiler/ValidateLimitations.cpp: Added.
+ (ValidateLimitations::ValidateLimitations):
+ (ValidateLimitations::visitSymbol):
+ (ValidateLimitations::visitConstantUnion):
+ (ValidateLimitations::visitBinary):
+ (ValidateLimitations::visitUnary):
+ (ValidateLimitations::visitSelection):
+ (ValidateLimitations::visitAggregate):
+ (ValidateLimitations::visitLoop):
+ (ValidateLimitations::visitBranch):
+ (ValidateLimitations::error):
+ (ValidateLimitations::withinLoopBody):
+ (ValidateLimitations::isLoopIndex):
+ (ValidateLimitations::validateLoopType):
+ (ValidateLimitations::validateForLoopHeader):
+ (ValidateLimitations::validateForLoopInit):
+ (ValidateLimitations::validateForLoopCond):
+ (ValidateLimitations::validateForLoopExpr):
+ (ValidateLimitations::validateFunctionCall):
+ (ValidateLimitations::validateOperation):
+ (ValidateLimitations::isConstExpr):
+ (ValidateLimitations::isConstIndexExpr):
+ (ValidateLimitations::validateIndexing):
+ * src/compiler/ValidateLimitations.h: Added.
+ (ValidateLimitations::numErrors):
+ * src/compiler/VariableInfo.cpp: Added.
+ (arrayBrackets):
+ (getVariableDataType):
+ (getVariableInfo):
+ (getBuiltInVariableInfo):
+ (getUserDefinedVariableInfo):
+ (CollectAttribsUniforms::CollectAttribsUniforms):
+ (CollectAttribsUniforms::visitSymbol):
+ (CollectAttribsUniforms::visitConstantUnion):
+ (CollectAttribsUniforms::visitBinary):
+ (CollectAttribsUniforms::visitUnary):
+ (CollectAttribsUniforms::visitSelection):
+ (CollectAttribsUniforms::visitAggregate):
+ (CollectAttribsUniforms::visitLoop):
+ (CollectAttribsUniforms::visitBranch):
+ * src/compiler/VariableInfo.h: Added.
+ * src/compiler/VersionGLSL.cpp: Added.
+ (TVersionGLSL::TVersionGLSL):
+ (TVersionGLSL::visitSymbol):
+ (TVersionGLSL::visitConstantUnion):
+ (TVersionGLSL::visitBinary):
+ (TVersionGLSL::visitUnary):
+ (TVersionGLSL::visitSelection):
+ (TVersionGLSL::visitAggregate):
+ (TVersionGLSL::visitLoop):
+ (TVersionGLSL::visitBranch):
+ (TVersionGLSL::updateVersion):
+ * src/compiler/VersionGLSL.h: Added.
+ (TVersionGLSL::getVersion):
+ * src/compiler/generate_glslang_lexer.sh: Added.
+ * src/compiler/generate_glslang_parser.sh: Added.
+ * src/compiler/glslang.h: Added.
+ * src/compiler/glslang.l:
+ * src/compiler/glslang.y:
+ * src/compiler/glslang_lex.cpp: Added.
+ (yy_get_next_buffer):
+ (yy_get_previous_state):
+ (yy_try_NUL_trans):
+ (input):
+ (yyrestart):
+ (yy_switch_to_buffer):
+ (yy_load_buffer_state):
+ (yy_create_buffer):
+ (yy_delete_buffer):
+ (yy_init_buffer):
+ (yy_flush_buffer):
+ (yypush_buffer_state):
+ (yypop_buffer_state):
+ (yyensure_buffer_stack):
+ (yy_scan_buffer):
+ (yy_scan_string):
+ (yy_scan_bytes):
+ (yy_push_state):
+ (yy_pop_state):
+ (yy_top_state):
+ (yy_fatal_error):
+ (yyget_extra):
+ (yyget_lineno):
+ (yyget_column):
+ (yyget_in):
+ (yyget_out):
+ (yyget_leng):
+ (yyget_text):
+ (yyset_extra):
+ (yyset_lineno):
+ (yyset_column):
+ (yyset_in):
+ (yyset_out):
+ (yyget_debug):
+ (yyset_debug):
+ (yyget_lval):
+ (yyset_lval):
+ (yylex_init):
+ (yylex_init_extra):
+ (yy_init_globals):
+ (yylex_destroy):
+ (yy_flex_strncpy):
+ (yy_flex_strlen):
+ (yyalloc):
+ (yyrealloc):
+ (yyfree):
+ (string_input):
+ (check_type):
+ (reserved_word):
+ (yyerror):
+ (glslang_initialize):
+ (glslang_finalize):
+ (glslang_scan):
+ * src/compiler/glslang_tab.cpp: Added.
+ (yytnamerr):
+ (yysyntax_error):
+ (glslang_parse):
+ * src/compiler/glslang_tab.h: Added.
+ * src/compiler/intermOut.cpp:
+ (TOutputTraverser::TOutputTraverser):
+ (OutputTreeText):
+ (TOutputTraverser::visitSymbol):
+ (TOutputTraverser::visitBinary):
+ (TOutputTraverser::visitUnary):
+ (TOutputTraverser::visitAggregate):
+ (TOutputTraverser::visitSelection):
+ (TOutputTraverser::visitConstantUnion):
+ (TOutputTraverser::visitLoop):
+ (TOutputTraverser::visitBranch):
+ (TIntermediate::outputTree):
+ * src/compiler/intermediate.h:
+ (TIntermLoop::TIntermLoop):
+ (TIntermLoop::getType):
+ (TIntermLoop::getInit):
+ (TIntermLoop::getCondition):
+ (TIntermLoop::getExpression):
+ (TIntermLoop::getBody):
+ * src/compiler/localintermediate.h:
+ * src/compiler/osinclude.h:
+ (OS_GetTLSValue):
+ * src/compiler/ossource_nspr.cpp: Added.
+ (OS_AllocTLSIndex):
+ (OS_SetTLSValue):
+ (OS_FreeTLSIndex):
+ * src/compiler/preprocessor/compile.h:
+ * src/compiler/preprocessor/cpp.c:
+ (CPPdefine):
+ (CPPelse):
+ (CPPif):
+ (CPPifdef):
+ (CPPerror):
+ (CPPextension):
+ (readCPPline):
+ * src/compiler/preprocessor/preprocess.h:
+ * src/compiler/preprocessor/scanner.c:
+ (str_getch):
+ (str_ungetch):
+ (ScanFromString):
+ (lFloatConst):
+ (byte_scan):
+ (yylex_CPP):
+ (check_EOF):
+ * src/compiler/preprocessor/scanner.h:
+ * src/compiler/preprocessor/tokens.c:
+ (RecordToken):
+ (ReadToken):
+ * src/compiler/tools: Removed.
+ * src/compiler/unistd.h: Removed.
+ * src/compiler/util.cpp: Added.
+ (atof_dot):
+ * src/compiler/util.h: Added.
+ * src/libEGL/Config.cpp:
+ (egl::Config::set):
+ * src/libEGL/Display.cpp:
+ (egl::Display::Display):
+ (egl::Display::initialize):
+ (egl::Display::terminate):
+ (egl::Display::createDevice):
+ (egl::Display::resetDevice):
+ (egl::Display::createContext):
+ (egl::Display::destroyContext):
+ (egl::Display::getMinSwapInterval):
+ (egl::Display::getMaxSwapInterval):
+ (egl::Display::getDevice):
+ (egl::Display::getFloatTextureSupport):
+ (egl::Display::getHalfFloatTextureSupport):
+ (egl::Display::getLuminanceTextureSupport):
+ (egl::Display::getLuminanceAlphaTextureSupport):
+ (egl::Display::getBufferPool):
+ (egl::Display::getEventQuerySupport):
+ (egl::Display::getDefaultPresentParameters):
+ * src/libEGL/Display.h:
+ * src/libEGL/Surface.cpp:
+ (egl::Surface::Surface):
+ (egl::Surface::~Surface):
+ (egl::Surface::release):
+ (egl::Surface::resetSwapChain):
+ (egl::Surface::writeRecordableFlipState):
+ (egl::Surface::restoreState):
+ (egl::SurfaceWindowProc):
+ (egl::Surface::subclassWindow):
+ (egl::Surface::unsubclassWindow):
+ (egl::Surface::checkForOutOfDateSwapChain):
+ (egl::Surface::convertInterval):
+ (egl::Surface::swap):
+ (egl::Surface::getRenderTarget):
+ (egl::Surface::setSwapInterval):
+ * src/libEGL/Surface.h:
+ * src/libEGL/libEGL.cpp:
+ * src/libGLESv2/Blit.cpp:
+ (gl::Blit::copySurfaceToTexture):
+ (gl::Blit::setCommonBlitState):
+ * src/libGLESv2/Buffer.cpp:
+ (gl::Buffer::Buffer):
+ (gl::Buffer::~Buffer):
+ (gl::Buffer::bufferData):
+ (gl::Buffer::bufferSubData):
+ (gl::Buffer::getVertexBuffer):
+ (gl::Buffer::getIndexBuffer):
+ (gl::Buffer::invalidateStaticData):
+ * src/libGLESv2/Buffer.h:
+ * src/libGLESv2/Context.cpp:
+ (gl::Context::Context):
+ (gl::Context::~Context):
+ (gl::Context::makeCurrent):
+ (gl::Context::markAllStateDirty):
+ (gl::Context::setFragmentShaderDerivativeHint):
+ (gl::Context::setEnableVertexAttribArray):
+ (gl::Context::getVertexAttribState):
+ (gl::Context::getVertexAttributes):
+ (gl::Context::createFence):
+ (gl::Context::deleteFence):
+ (gl::Context::bindTexture2D):
+ (gl::Context::bindTextureCubeMap):
+ (gl::Context::getFence):
+ (gl::Context::getTexture2D):
+ (gl::Context::getTextureCubeMap):
+ (gl::Context::getSamplerTexture):
+ (gl::Context::getBooleanv):
+ (gl::Context::getIntegerv):
+ (gl::Context::getQueryParameterInfo):
+ (gl::Context::applyRenderTarget):
+ (gl::Context::applyState):
+ (gl::Context::lookupAttributeMapping):
+ (gl::Context::applyVertexBuffer):
+ (gl::Context::applyIndexBuffer):
+ (gl::Context::readPixels):
+ (gl::Context::clear):
+ (gl::Context::drawArrays):
+ (gl::Context::drawElements):
+ (gl::Context::finish):
+ (gl::Context::drawClosingLine):
+ (gl::Context::getMaximumVaryingVectors):
+ (gl::Context::getMaximumFragmentUniformVectors):
+ (gl::Context::supportsEventQueries):
+ (gl::Context::supportsFloatTextures):
+ (gl::Context::supportsFloatLinearFilter):
+ (gl::Context::supportsFloatRenderableTextures):
+ (gl::Context::supportsHalfFloatTextures):
+ (gl::Context::supportsHalfFloatLinearFilter):
+ (gl::Context::supportsHalfFloatRenderableTextures):
+ (gl::Context::getMaximumRenderbufferDimension):
+ (gl::Context::getMaximumTextureDimension):
+ (gl::Context::getMaximumCubeTextureDimension):
+ (gl::Context::getMaximumTextureLevel):
+ (gl::Context::supportsLuminanceTextures):
+ (gl::Context::supportsLuminanceAlphaTextures):
+ (gl::Context::supports32bitIndices):
+ (gl::Context::getIncompleteTexture):
+ (gl::Context::setVertexAttrib):
+ (gl::Context::initExtensionString):
+ (gl::Context::blitFramebuffer):
+ * src/libGLESv2/Context.h:
+ (gl::VertexAttribute::VertexAttribute):
+ (gl::VertexAttribute::typeSize):
+ (gl::VertexAttribute::stride):
+ * src/libGLESv2/Fence.cpp: Added.
+ (gl::Fence::Fence):
+ (gl::Fence::~Fence):
+ (gl::Fence::isFence):
+ (gl::Fence::setFence):
+ (gl::Fence::testFence):
+ (gl::Fence::finishFence):
+ (gl::Fence::getFenceiv):
+ * src/libGLESv2/Fence.h: Added.
+ * src/libGLESv2/Framebuffer.cpp:
+ (gl::Framebuffer::completeness):
+ (gl::DefaultFramebuffer::DefaultFramebuffer):
+ (gl::DefaultFramebuffer::completeness):
+ * src/libGLESv2/Program.cpp:
+ (gl::Program::Program):
+ (gl::Program::getSamplerMapping):
+ (gl::Program::getUniformLocation):
+ (gl::Program::setUniform1iv):
+ (gl::Program::applyUniforms):
+ (gl::Program::packVaryings):
+ (gl::Program::linkVaryings):
+ (gl::Program::link):
+ (gl::Program::defineUniform):
+ (gl::Program::createUniform):
+ (gl::Program::applyUniform1iv):
+ (gl::Program::resetInfoLog):
+ (gl::Program::unlink):
+ (gl::Program::getActiveAttribute):
+ (gl::Program::getActiveUniform):
+ (gl::Program::getDxDepthRangeLocation):
+ * src/libGLESv2/Program.h:
+ * src/libGLESv2/RefCountObject.cpp:
+ (gl::RefCountObject::~RefCountObject):
+ * src/libGLESv2/Renderbuffer.cpp:
+ (gl::RenderbufferStorage::RenderbufferStorage):
+ (gl::RenderbufferStorage::isFloatingPoint):
+ (gl::Colorbuffer::Colorbuffer):
+ (gl::DepthStencilbuffer::DepthStencilbuffer):
+ * src/libGLESv2/Renderbuffer.h:
+ * src/libGLESv2/Shader.cpp:
+ (gl::Shader::Shader):
+ (gl::Shader::parseVaryings):
+ (gl::Shader::compileToHLSL):
+ (gl::VertexShader::parseAttributes):
+ * src/libGLESv2/Texture.cpp:
+ (gl::Texture::Texture):
+ (gl::Texture::isFloatingPoint):
+ (gl::Texture::isRenderableFormat):
+ (gl::Texture::selectFormat):
+ (gl::Texture::loadImageData):
+ (gl::Texture::loadAlphaFloatImageData):
+ (gl::Texture::loadAlphaHalfFloatImageData):
+ (gl::Texture::loadLuminanceImageData):
+ (gl::Texture::loadLuminanceFloatImageData):
+ (gl::Texture::loadLuminanceHalfFloatImageData):
+ (gl::Texture::loadLuminanceAlphaImageData):
+ (gl::Texture::loadLuminanceAlphaFloatImageData):
+ (gl::Texture::loadLuminanceAlphaHalfFloatImageData):
+ (gl::Texture::loadRGBFloatImageData):
+ (gl::Texture::loadRGBHalfFloatImageData):
+ (gl::Texture::loadRGBAFloatImageData):
+ (gl::Texture::loadRGBAHalfFloatImageData):
+ (gl::Texture::createSurface):
+ (gl::Texture::setImage):
+ (gl::Texture::setCompressedImage):
+ (gl::Texture::subImage):
+ (gl::Texture::subImageCompressed):
+ (gl::Texture::copyNonRenderable):
+ (gl::Texture::getD3DFormat):
+ (gl::Texture::isRenderable):
+ (gl::Texture2D::Texture2D):
+ (gl::Texture2D::~Texture2D):
+ (gl::Texture2D::redefineTexture):
+ (gl::Texture2D::setImage):
+ (gl::Texture2D::setCompressedImage):
+ (gl::Texture2D::copyImage):
+ (gl::Texture2D::copySubImage):
+ (gl::Texture2D::isComplete):
+ (gl::Texture2D::createTexture):
+ (gl::Texture2D::convertToRenderTarget):
+ (gl::Texture2D::generateMipmaps):
+ (gl::Texture2D::getColorbuffer):
+ (gl::Texture2D::getRenderTarget):
+ (gl::TextureCubeMap::TextureCubeMap):
+ (gl::TextureCubeMap::~TextureCubeMap):
+ (gl::TextureCubeMap::subImage):
+ (gl::TextureCubeMap::subImageCompressed):
+ (gl::TextureCubeMap::isComplete):
+ (gl::TextureCubeMap::createTexture):
+ (gl::TextureCubeMap::convertToRenderTarget):
+ (gl::TextureCubeMap::redefineTexture):
+ (gl::TextureCubeMap::copyImage):
+ (gl::TextureCubeMap::copySubImage):
+ (gl::TextureCubeMap::generateMipmaps):
+ (gl::TextureCubeMap::getColorbuffer):
+ (gl::TextureCubeMap::getRenderTarget):
+ (gl::Texture::TextureColorbufferProxy::TextureColorbufferProxy):
+ (gl::Texture::TextureColorbufferProxy::isFloatingPoint):
+ * src/libGLESv2/Texture.h:
+ * src/libGLESv2/geometry/IndexDataManager.cpp:
+ (gl::IndexDataManager::IndexDataManager):
+ (gl::IndexDataManager::~IndexDataManager):
+ (gl::convertIndices):
+ (gl::computeRange):
+ (gl::IndexDataManager::prepareIndexData):
+ (gl::IndexDataManager::indexSize):
+ (gl::IndexDataManager::typeSize):
+ (gl::IndexBuffer::IndexBuffer):
+ (gl::IndexBuffer::~IndexBuffer):
+ (gl::IndexBuffer::getBuffer):
+ (gl::IndexBuffer::unmap):
+ (gl::StreamingIndexBuffer::StreamingIndexBuffer):
+ (gl::StreamingIndexBuffer::~StreamingIndexBuffer):
+ (gl::StreamingIndexBuffer::map):
+ (gl::StreamingIndexBuffer::reserveSpace):
+ (gl::StaticIndexBuffer::StaticIndexBuffer):
+ (gl::StaticIndexBuffer::~StaticIndexBuffer):
+ (gl::StaticIndexBuffer::map):
+ (gl::StaticIndexBuffer::reserveSpace):
+ (gl::StaticIndexBuffer::lookupType):
+ (gl::StaticIndexBuffer::lookupRange):
+ (gl::StaticIndexBuffer::addRange):
+ * src/libGLESv2/geometry/IndexDataManager.h:
+ (gl::IndexBuffer::size):
+ * src/libGLESv2/geometry/VertexDataManager.cpp:
+ (gl::VertexDataManager::VertexDataManager):
+ (gl::VertexDataManager::~VertexDataManager):
+ (gl::VertexDataManager::writeAttributeData):
+ (gl::VertexDataManager::prepareVertexData):
+ (gl::VertexDataManager::spaceRequired):
+ (gl::VertexDataManager::checkVertexCaps):
+ (gl::VertexDataManager::typeIndex):
+ (gl::VertexDataManager::setupAttributes):
+ (gl::VertexBuffer::VertexBuffer):
+ (gl::VertexBuffer::~VertexBuffer):
+ (gl::VertexBuffer::unmap):
+ (gl::VertexBuffer::getBuffer):
+ (gl::ConstantVertexBuffer::ConstantVertexBuffer):
+ (gl::ConstantVertexBuffer::~ConstantVertexBuffer):
+ (gl::ArrayVertexBuffer::ArrayVertexBuffer):
+ (gl::ArrayVertexBuffer::~ArrayVertexBuffer):
+ (gl::ArrayVertexBuffer::addRequiredSpace):
+ (gl::ArrayVertexBuffer::addRequiredSpaceFor):
+ (gl::StreamingVertexBuffer::StreamingVertexBuffer):
+ (gl::StreamingVertexBuffer::~StreamingVertexBuffer):
+ (gl::StreamingVertexBuffer::map):
+ (gl::StreamingVertexBuffer::reserveRequiredSpace):
+ (gl::StaticVertexBuffer::StaticVertexBuffer):
+ (gl::StaticVertexBuffer::~StaticVertexBuffer):
+ (gl::StaticVertexBuffer::map):
+ (gl::StaticVertexBuffer::reserveRequiredSpace):
+ (gl::StaticVertexBuffer::lookupAttribute):
+ (gl::VertexDataManager::formatConverter):
+ * src/libGLESv2/geometry/VertexDataManager.h:
+ (gl::ArrayVertexBuffer::size):
+ (gl::VertexDataManager::dirtyCurrentValue):
+ * src/libGLESv2/geometry/backend.cpp: Removed.
+ * src/libGLESv2/geometry/backend.h: Removed.
+ * src/libGLESv2/geometry/dx9.cpp: Removed.
+ * src/libGLESv2/geometry/dx9.h: Removed.
+ * src/libGLESv2/libGLESv2.cpp:
+ * src/libGLESv2/libGLESv2.def:
+ * src/libGLESv2/libGLESv2.vcproj:
+ * src/libGLESv2/utilities.cpp:
+ (gl::UniformComponentCount):
+ (gl::UniformComponentType):
+ (gl::ComputePixelSize):
+ (gl::CheckTextureFormatType):
+ (gl::IsColorRenderable):
+ (gl::IsDepthRenderable):
+ (gl::IsStencilRenderable):
+ (es2dx::GetAlphaSize):
+ (es2dx::GetRedSize):
+ (es2dx::GetGreenSize):
+ (es2dx::GetBlueSize):
+ (es2dx::GetDepthSize):
+ (es2dx::ConvertPrimitiveType):
+ (dx2es::ConvertBackBufferFormat):
+ (dx2es::ConvertDepthStencilFormat):
+ * src/libGLESv2/utilities.h:
+
+2011-01-17 Dan Bernstein <mitz@apple.com>
+
+ Rubber-stamped by Mark Rowe.
+
+ Update xcodeproj svn:ignore to include xcuserdata.
+
+ * ANGLE.xcodeproj: Modified property svn:ignore.
+ * src/build_angle.xcodeproj: Modified property svn:ignore.
+
+2010-12-01 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ vcproj changes can't be applied cleanly by the Windows EWS bot
+ https://bugs.webkit.org/show_bug.cgi?id=50328
+
+ * src/libEGL/libEGL.vcproj: Added property svn:eol-style.
+ * src/libGLESv2/libGLESv2.vcproj: Added property svn:eol-style.
+
+2010-11-03 Darin Adler <darin@apple.com>
+
+ Updated Xcode projects by opening them with Xcode 3.2.4.
+ Updated svn:ignore for Xcode projects.
+
+ * ANGLE.xcodeproj: Added property svn:ignore.
+ * ANGLE.xcodeproj/project.pbxproj: Updated with Xcode 3.2.4.
+ * src/build_angle.xcodeproj: Added property svn:ignore.
+ * src/build_angle.xcodeproj/project.pbxproj: Updated with Xcode 3.2.4.
+
+2010-09-01 Zhenyao Mo <zmo@google.com>
+
+ Reviewed by Kenneth Russell.
+
+ Roll ANGLE under webkit to r402
+ https://bugs.webkit.org/show_bug.cgi?id=45004
+
+ * ANGLE.xcodeproj/project.pbxproj:
+ * include/GLES2/gl2ext.h:
+ * include/GLSLANG/ResourceLimits.h: Removed.
+ * include/GLSLANG/ShaderLang.h:
+ * src/compiler/BaseTypes.h:
+ (getPrecisionString):
+ (getBasicString):
+ (IsSampler):
+ (getQualifierString):
+ * src/compiler/Initialize.cpp:
+ (BuiltInConstants):
+ (IdentifyBuiltIns):
+ * src/compiler/Initialize.h:
+ * src/compiler/InitializeDll.cpp:
+ (InitProcess):
+ (DetachProcess):
+ (InitThread):
+ (DetachThread):
+ * src/compiler/InitializeDll.h:
+ * src/compiler/InitializeParseContext.h:
+ * src/compiler/Intermediate.cpp:
+ (GetHigherPrecision):
+ (TIntermediate::addBinaryMath):
+ (TIntermediate::setAggregateOperator):
+ (TIntermediate::addComma):
+ (TIntermediate::postProcess):
+ (TIntermBinary::promote):
+ (CompareStruct):
+ * src/compiler/OutputGLSL.cpp:
+ (TOutputGLSL::writeFunctionParameters):
+ (TOutputGLSL::visitUnary):
+ (TOutputGLSL::visitBranch):
+ * src/compiler/OutputHLSL.cpp:
+ (sh::OutputHLSL::header):
+ (sh::OutputHLSL::visitBinary):
+ (sh::OutputHLSL::visitAggregate):
+ (sh::OutputHLSL::handleExcessiveLoop):
+ (sh::OutputHLSL::addConstructor):
+ * src/compiler/ParseHelper.cpp:
+ (TParseContext::constructorErrorCheck):
+ (TParseContext::samplerErrorCheck):
+ (TParseContext::paramErrorCheck):
+ (TParseContext::findFunction):
+ (TParseContext::executeInitializer):
+ (TParseContext::addConstructor):
+ (TParseContext::addConstStruct):
+ (FreeParseContextIndex):
+ (GetGlobalParseContext):
+ * src/compiler/PoolAlloc.h:
+ (TPoolAllocator::tHeader::tHeader):
+ (pool_allocator::allocate):
+ (pool_allocator::deallocate):
+ * src/compiler/ShaderLang.cpp:
+ (ShInitialize):
+ (ShFinalize):
+ (ShInitBuiltInResource):
+ * src/compiler/SymbolTable.cpp:
+ (TType::getStructSize):
+ * src/compiler/SymbolTable.h:
+ (TVariable::setQualifier):
+ * src/compiler/Types.h:
+ (TType::TType):
+ (TType::getBasicType):
+ (TType::setBasicType):
+ (TType::getPrecision):
+ (TType::setPrecision):
+ (TType::getQualifier):
+ (TType::setQualifier):
+ (TType::getNominalSize):
+ (TType::setNominalSize):
+ (TType::isMatrix):
+ (TType::setMatrix):
+ (TType::isArray):
+ (TType::getArraySize):
+ (TType::setArraySize):
+ (TType::getMaxArraySize):
+ (TType::setMaxArraySize):
+ (TType::clearArrayness):
+ (TType::setArrayInformationType):
+ (TType::getArrayInformationType):
+ (TType::isVector):
+ (TType::isScalar):
+ (TType::setStruct):
+ (TType::getTypeName):
+ (TType::setTypeName):
+ (TType::isField):
+ (TType::getFieldName):
+ (TType::setFieldName):
+ (TType::getBasicString):
+ (TType::getPrecisionString):
+ (TType::getQualifierString):
+ * src/compiler/glslang.l:
+ * src/compiler/glslang.y:
+ * src/compiler/intermediate.h:
+ (TIntermNode::getLine):
+ (TIntermNode::setLine):
+ (TIntermTyped::getAsTyped):
+ (TIntermTyped::setType):
+ (TIntermTyped::getType):
+ (TIntermTyped::getTypePointer):
+ (TIntermTyped::getBasicType):
+ (TIntermTyped::getQualifier):
+ (TIntermTyped::getPrecision):
+ (TIntermTyped::getNominalSize):
+ (TIntermTyped::isMatrix):
+ (TIntermTyped::isArray):
+ (TIntermTyped::isVector):
+ (TIntermTyped::isScalar):
+ (TIntermTyped::getBasicString):
+ (TIntermTyped::getQualifierString):
+ (TIntermSymbol::getId):
+ (TIntermSymbol::getSymbol):
+ (TIntermOperator::setOp):
+ (TIntermBinary::setLeft):
+ (TIntermBinary::setRight):
+ (TIntermBinary::getLeft):
+ (TIntermBinary::getRight):
+ (TIntermUnary::setOperand):
+ (TIntermUnary::getOperand):
+ (TIntermAggregate::getAsAggregate):
+ (TIntermAggregate::getSequence):
+ (TIntermAggregate::setName):
+ (TIntermAggregate::getName):
+ (TIntermAggregate::setUserDefined):
+ (TIntermAggregate::isUserDefined):
+ (TIntermAggregate::getQualifier):
+ (TIntermAggregate::setOptimize):
+ (TIntermAggregate::setDebug):
+ (TIntermSelection::getCondition):
+ (TIntermSelection::getTrueBlock):
+ (TIntermSelection::getFalseBlock):
+ (TIntermSelection::getAsSelectionNode):
+ * src/compiler/parseConst.cpp:
+ (TConstTraverser::TConstTraverser):
+ * src/compiler/preprocessor/atom.c:
+ (InitAtomTable):
+ * src/compiler/preprocessor/atom.h:
+ * src/compiler/preprocessor/compile.h:
+ * src/compiler/preprocessor/cpp.c:
+ * src/compiler/preprocessor/cpp.h:
+ * src/compiler/preprocessor/cppstruct.c:
+ * src/compiler/preprocessor/memory.c:
+ * src/compiler/preprocessor/memory.h:
+ * src/compiler/preprocessor/parser.h:
+ * src/compiler/preprocessor/preprocess.h:
+ * src/compiler/preprocessor/scanner.c:
+ * src/compiler/preprocessor/scanner.h:
+ * src/compiler/preprocessor/slglobals.h:
+ * src/compiler/preprocessor/symbols.c:
+ (NewSymbol):
+ * src/compiler/preprocessor/symbols.h:
+ * src/compiler/preprocessor/tokens.c:
+ (RecordToken):
+ * src/compiler/preprocessor/tokens.h:
+ * src/libEGL/Display.cpp:
+ (egl::Display::Display):
+ (egl::Display::initialize):
+ (egl::Display::terminate):
+ (egl::Display::createDevice):
+ (egl::Display::createWindowSurface):
+ (egl::Display::createContext):
+ (egl::Display::getMultiSampleSupport):
+ (egl::Display::getCompressedTextureSupport):
+ * src/libEGL/Display.h:
+ * src/libEGL/Surface.cpp:
+ (egl::Surface::Surface):
+ (egl::Surface::resetSwapChain):
+ (egl::Surface::getWindowHandle):
+ (egl::Surface::writeRecordableFlipState):
+ (egl::Surface::applyFlipState):
+ (egl::Surface::releaseRecordedState):
+ (egl::Surface::checkForWindowResize):
+ (egl::Surface::swap):
+ * src/libEGL/Surface.h:
+ * src/libEGL/libEGL.cpp:
+ * src/libEGL/libEGL.vcproj:
+ * src/libGLESv2/Blit.cpp:
+ (gl::Blit::setVertexShader):
+ (gl::Blit::setPixelShader):
+ (gl::Blit::setFormatConvertShaders):
+ * src/libGLESv2/Buffer.cpp:
+ (gl::Buffer::Buffer):
+ * src/libGLESv2/Buffer.h:
+ * src/libGLESv2/Context.cpp:
+ (gl::Context::Context):
+ (gl::Context::~Context):
+ (gl::Context::makeCurrent):
+ (gl::Context::markAllStateDirty):
+ (gl::Context::getReadFramebufferHandle):
+ (gl::Context::getDrawFramebufferHandle):
+ (gl::Context::getRenderbufferHandle):
+ (gl::Context::getArrayBufferHandle):
+ (gl::Context::setVertexAttribState):
+ (gl::Context::createBuffer):
+ (gl::Context::createProgram):
+ (gl::Context::createShader):
+ (gl::Context::createTexture):
+ (gl::Context::createRenderbuffer):
+ (gl::Context::deleteBuffer):
+ (gl::Context::deleteShader):
+ (gl::Context::deleteProgram):
+ (gl::Context::deleteTexture):
+ (gl::Context::deleteRenderbuffer):
+ (gl::Context::getBuffer):
+ (gl::Context::getShader):
+ (gl::Context::getProgram):
+ (gl::Context::getTexture):
+ (gl::Context::getRenderbuffer):
+ (gl::Context::getReadFramebuffer):
+ (gl::Context::getDrawFramebuffer):
+ (gl::Context::bindArrayBuffer):
+ (gl::Context::bindElementArrayBuffer):
+ (gl::Context::bindTexture2D):
+ (gl::Context::bindTextureCubeMap):
+ (gl::Context::bindReadFramebuffer):
+ (gl::Context::bindDrawFramebuffer):
+ (gl::Context::bindRenderbuffer):
+ (gl::Context::useProgram):
+ (gl::Context::setFramebufferZero):
+ (gl::Context::setRenderbufferStorage):
+ (gl::Context::getFramebuffer):
+ (gl::Context::getArrayBuffer):
+ (gl::Context::getElementArrayBuffer):
+ (gl::Context::getCurrentProgram):
+ (gl::Context::getTexture2D):
+ (gl::Context::getTextureCubeMap):
+ (gl::Context::getSamplerTexture):
+ (gl::Context::getFloatv):
+ (gl::Context::getIntegerv):
+ (gl::Context::getQueryParameterInfo):
+ (gl::Context::applyRenderTarget):
+ (gl::Context::applyState):
+ (gl::Context::applyIndexBuffer):
+ (gl::Context::readPixels):
+ (gl::Context::clear):
+ (gl::Context::finish):
+ (gl::Context::flush):
+ (gl::Context::supportsShaderModel3):
+ (gl::Context::getMaxSupportedSamples):
+ (gl::Context::getNearestSupportedSamples):
+ (gl::Context::supportsCompressedTextures):
+ (gl::Context::detachBuffer):
+ (gl::Context::detachTexture):
+ (gl::Context::detachFramebuffer):
+ (gl::Context::detachRenderbuffer):
+ (gl::Context::getIncompleteTexture):
+ (gl::Context::initExtensionString):
+ (gl::Context::blitFramebuffer):
+ * src/libGLESv2/Context.h:
+ (gl::AttributeState::AttributeState):
+ * src/libGLESv2/Framebuffer.cpp:
+ (gl::Framebuffer::Framebuffer):
+ (gl::Framebuffer::~Framebuffer):
+ (gl::Framebuffer::lookupRenderbuffer):
+ (gl::Framebuffer::setColorbuffer):
+ (gl::Framebuffer::setDepthbuffer):
+ (gl::Framebuffer::setStencilbuffer):
+ (gl::Framebuffer::detachTexture):
+ (gl::Framebuffer::detachRenderbuffer):
+ (gl::Framebuffer::getRenderTargetSerial):
+ (gl::Framebuffer::getRenderTarget):
+ (gl::Framebuffer::getDepthStencil):
+ (gl::Framebuffer::getDepthbufferSerial):
+ (gl::Framebuffer::getStencilbufferSerial):
+ (gl::Framebuffer::getColorbuffer):
+ (gl::Framebuffer::getDepthbuffer):
+ (gl::Framebuffer::getStencilbuffer):
+ (gl::Framebuffer::getColorbufferHandle):
+ (gl::Framebuffer::getDepthbufferHandle):
+ (gl::Framebuffer::getStencilbufferHandle):
+ (gl::Framebuffer::hasStencil):
+ (gl::Framebuffer::isMultisample):
+ (gl::Framebuffer::completeness):
+ (gl::DefaultFramebuffer::DefaultFramebuffer):
+ (gl::Framebuffer::getSamples):
+ (gl::DefaultFramebuffer::completeness):
+ * src/libGLESv2/Framebuffer.h:
+ * src/libGLESv2/Program.cpp:
+ (gl::Program::Program):
+ (gl::Program::~Program):
+ (gl::Program::attachShader):
+ (gl::Program::detachShader):
+ (gl::Program::linkVaryings):
+ (gl::Program::link):
+ (gl::Program::unlink):
+ (gl::Program::release):
+ (gl::Program::addRef):
+ (gl::Program::getRefCount):
+ (gl::Program::getDxViewportLocation):
+ * src/libGLESv2/Program.h:
+ * src/libGLESv2/RefCountObject.cpp: Added.
+ (gl::RefCountObject::RefCountObject):
+ (gl::RefCountObject::~RefCountObject):
+ (gl::RefCountObject::addRef):
+ (gl::RefCountObject::release):
+ (gl::RefCountObjectBindingPointer::set):
+ * src/libGLESv2/RefCountObject.h: Added.
+ (gl::RefCountObject::id):
+ (gl::RefCountObjectBindingPointer::RefCountObjectBindingPointer):
+ (gl::RefCountObjectBindingPointer::~RefCountObjectBindingPointer):
+ (gl::RefCountObjectBindingPointer::get):
+ (gl::RefCountObjectBindingPointer::id):
+ (gl::RefCountObjectBindingPointer::operator ! ):
+ (gl::BindingPointer::set):
+ (gl::BindingPointer::get):
+ (gl::BindingPointer::operator -> ):
+ * src/libGLESv2/Renderbuffer.cpp:
+ (gl::Renderbuffer::Renderbuffer):
+ (gl::Renderbuffer::~Renderbuffer):
+ (gl::Renderbuffer::isColorbuffer):
+ (gl::Renderbuffer::isDepthbuffer):
+ (gl::Renderbuffer::isStencilbuffer):
+ (gl::Renderbuffer::getRenderTarget):
+ (gl::Renderbuffer::getDepthStencil):
+ (gl::Renderbuffer::getWidth):
+ (gl::Renderbuffer::getHeight):
+ (gl::Renderbuffer::getFormat):
+ (gl::Renderbuffer::getD3DFormat):
+ (gl::Renderbuffer::getSerial):
+ (gl::Renderbuffer::setStorage):
+ (gl::RenderbufferStorage::RenderbufferStorage):
+ (gl::RenderbufferStorage::~RenderbufferStorage):
+ (gl::RenderbufferStorage::isColorbuffer):
+ (gl::RenderbufferStorage::isDepthbuffer):
+ (gl::RenderbufferStorage::isStencilbuffer):
+ (gl::RenderbufferStorage::getRenderTarget):
+ (gl::RenderbufferStorage::getDepthStencil):
+ (gl::RenderbufferStorage::getWidth):
+ (gl::RenderbufferStorage::getHeight):
+ (gl::RenderbufferStorage::setSize):
+ (gl::RenderbufferStorage::getFormat):
+ (gl::RenderbufferStorage::getD3DFormat):
+ (gl::RenderbufferStorage::getSamples):
+ (gl::RenderbufferStorage::getSerial):
+ (gl::RenderbufferStorage::issueSerial):
+ (gl::Colorbuffer::Colorbuffer):
+ (gl::Colorbuffer::isColorbuffer):
+ (gl::Colorbuffer::getRedSize):
+ (gl::Colorbuffer::getGreenSize):
+ (gl::Colorbuffer::getBlueSize):
+ (gl::Colorbuffer::getAlphaSize):
+ (gl::DepthStencilbuffer::DepthStencilbuffer):
+ (gl::DepthStencilbuffer::~DepthStencilbuffer):
+ (gl::DepthStencilbuffer::isDepthbuffer):
+ (gl::DepthStencilbuffer::isStencilbuffer):
+ (gl::DepthStencilbuffer::getDepthSize):
+ (gl::DepthStencilbuffer::getStencilSize):
+ (gl::DepthStencilbuffer::getDepthStencil):
+ (gl::Depthbuffer::Depthbuffer):
+ (gl::Depthbuffer::~Depthbuffer):
+ (gl::Depthbuffer::isDepthbuffer):
+ (gl::Depthbuffer::isStencilbuffer):
+ (gl::Stencilbuffer::Stencilbuffer):
+ (gl::Stencilbuffer::~Stencilbuffer):
+ (gl::Stencilbuffer::isDepthbuffer):
+ (gl::Stencilbuffer::isStencilbuffer):
+ * src/libGLESv2/Renderbuffer.h:
+ (gl::Renderbuffer::getStorage):
+ * src/libGLESv2/ResourceManager.cpp: Added.
+ (gl::ResourceManager::ResourceManager):
+ (gl::ResourceManager::~ResourceManager):
+ (gl::ResourceManager::addRef):
+ (gl::ResourceManager::release):
+ (gl::ResourceManager::createBuffer):
+ (gl::ResourceManager::createShader):
+ (gl::ResourceManager::createProgram):
+ (gl::ResourceManager::createTexture):
+ (gl::ResourceManager::createRenderbuffer):
+ (gl::ResourceManager::deleteBuffer):
+ (gl::ResourceManager::deleteShader):
+ (gl::ResourceManager::deleteProgram):
+ (gl::ResourceManager::deleteTexture):
+ (gl::ResourceManager::deleteRenderbuffer):
+ (gl::ResourceManager::getBuffer):
+ (gl::ResourceManager::getShader):
+ (gl::ResourceManager::getTexture):
+ (gl::ResourceManager::getProgram):
+ (gl::ResourceManager::getRenderbuffer):
+ (gl::ResourceManager::setRenderbuffer):
+ (gl::ResourceManager::checkBufferAllocation):
+ (gl::ResourceManager::checkTextureAllocation):
+ (gl::ResourceManager::checkRenderbufferAllocation):
+ * src/libGLESv2/ResourceManager.h: Added.
+ * src/libGLESv2/Shader.cpp:
+ (gl::Shader::Shader):
+ (gl::Shader::addRef):
+ (gl::Shader::release):
+ (gl::Shader::getRefCount):
+ (gl::Shader::parseVaryings):
+ (gl::VertexShader::VertexShader):
+ (gl::FragmentShader::FragmentShader):
+ * src/libGLESv2/Shader.h:
+ * src/libGLESv2/Texture.cpp:
+ (gl::Texture::Image::Image):
+ (gl::Texture::Texture):
+ (gl::Texture::getBlitter):
+ (gl::Texture::selectFormat):
+ (gl::Texture::loadImageData):
+ (gl::Texture::loadAlphaImageData):
+ (gl::Texture::loadLuminanceImageData):
+ (gl::Texture::loadLuminanceAlphaImageData):
+ (gl::Texture::loadRGBUByteImageData):
+ (gl::Texture::loadRGB565ImageData):
+ (gl::Texture::loadRGBAUByteImageData):
+ (gl::Texture::loadRGBA4444ImageData):
+ (gl::Texture::loadRGBA5551ImageData):
+ (gl::Texture::loadBGRAImageData):
+ (gl::Texture::createSurface):
+ (gl::Texture::setImage):
+ (gl::Texture::setCompressedImage):
+ (gl::Texture::subImage):
+ (gl::Texture::subImageCompressed):
+ (gl::Texture2D::Texture2D):
+ (gl::Texture2D::getFormat):
+ (gl::Texture2D::setCompressedImage):
+ (gl::Texture2D::subImage):
+ (gl::Texture2D::subImageCompressed):
+ (gl::Texture2D::copyImage):
+ (gl::Texture2D::copySubImage):
+ (gl::Texture2D::isCompressed):
+ (gl::Texture2D::getColorbuffer):
+ (gl::TextureCubeMap::TextureCubeMap):
+ (gl::TextureCubeMap::getFormat):
+ (gl::TextureCubeMap::setCompressedImage):
+ (gl::TextureCubeMap::subImage):
+ (gl::TextureCubeMap::subImageCompressed):
+ (gl::TextureCubeMap::isCompressed):
+ (gl::TextureCubeMap::copyImage):
+ (gl::TextureCubeMap::copySubImage):
+ (gl::TextureCubeMap::getColorbuffer):
+ (gl::Texture::TextureColorbufferProxy::addRef):
+ (gl::Texture::TextureColorbufferProxy::release):
+ (gl::Texture::TextureColorbufferProxy::getWidth):
+ (gl::Texture::TextureColorbufferProxy::getHeight):
+ (gl::Texture::TextureColorbufferProxy::getFormat):
+ * src/libGLESv2/Texture.h:
+ * src/libGLESv2/libGLESv2.cpp:
+ * src/libGLESv2/libGLESv2.def:
+ * src/libGLESv2/libGLESv2.vcproj:
+ * src/libGLESv2/main.h:
+ * src/libGLESv2/utilities.cpp:
+ (gl::ComputeCompressedPitch):
+ (gl::ComputeCompressedSize):
+ (gl::IsCompressed):
+ (gl::ComputePixelSize):
+ (gl::CheckTextureFormatType):
+ (es2dx::ConvertRenderbufferFormat):
+ (es2dx::GetSamplesFromMultisampleType):
+ (es2dx::GetMultisampleTypeFromSamples):
+ * src/libGLESv2/utilities.h:
+
+2010-08-17 Chris Marrin <cmarrin@apple.com>
+
+ Unreviewed.
+
+ Moved previous link error fix to Base.xcconfig.
+
+ * ANGLE.xcodeproj/project.pbxproj:
+ * Configurations/Base.xcconfig:
+
+2010-08-17 Chris Marrin <cmarrin@apple.com>
+
+ Unreviewed.
+
+ Got rid of link errors in WebCore.
+
+ Changed GCC_INLINES_ARE_PRIVATE_EXTERN to YES and
+ GCC_SYMBOLS_PRIVATE_EXTERN to NO to match WebCore
+ flags.
+
+ * ANGLE.xcodeproj/project.pbxproj:
+
+2010-08-04 Kenneth Russell <kbr@google.com>
+
+ Reviewed by Dimitri Glazkov.
+
+ Update ANGLE to r352
+ https://bugs.webkit.org/show_bug.cgi?id=43500
+
+ Updated ANGLE to r352 (July 26, 2010). Built WebKit to test.
+
+ * include/GLSLANG/ShaderLang.h:
+ * src/compiler/Initialize.cpp:
+ (BuiltInFunctionsCommon):
+ (BuiltInFunctionsVertex):
+ (BuiltInFunctionsFragment):
+ (StandardUniforms):
+ (DefaultPrecisionVertex):
+ (DefaultPrecisionFragment):
+ (BuiltInConstants):
+ (TBuiltIns::initialize):
+ (IdentifyBuiltIns):
+ * src/compiler/Initialize.h:
+ (TBuiltIns::getBuiltInStrings):
+ * src/compiler/OutputGLSL.cpp:
+ (TOutputGLSL::visitSelection):
+ * src/compiler/ShHandle.h:
+ (TCompiler::getLanguage):
+ (TCompiler::getSpec):
+ (TCompiler::getSymbolTable):
+ (TCompiler::getInfoSink):
+ * src/compiler/ShaderLang.cpp:
+ (InitializeSymbolTable):
+ (GenerateBuiltInSymbolTable):
+ (ShInitialize):
+ (ShConstructCompiler):
+ (ShFinalize):
+ (ShCompile):
+ * src/compiler/SymbolTable.h:
+ (TSymbolTable::atBuiltInLevel):
+ (TSymbolTable::atGlobalLevel):
+ (TSymbolTable::push):
+ (TSymbolTable::getGlobalLevel):
+ (TSymbolTable::currentLevel):
+ * src/libGLESv2/Shader.cpp:
+ (gl::Shader::Shader):
+ (gl::Shader::compileToHLSL):
+
+2010-08-03 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Adele Peterson.
+
+ Remove some unnecessary files from the ANGLE tree.
+
+ * src/compiler/tools/COPYING.bison: Removed.
+ * src/compiler/tools/COPYING.flex: Removed.
+ * src/compiler/tools/README: Removed.
+ * src/compiler/tools/bison.hairy: Removed.
+ * src/compiler/tools/bison.simple: Removed.
+
+2010-08-03 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Adele Peterson.
+
+ Clean up the ANGLE Xcode project.
+
+ Main changes include:
+ • Adding a Production configuration.
+ • Modifying the library name from libangle.a to libANGLE.a.
+ • Installing the headers in a subdirectory of /usr/local/include to avoid polluting the top-level directory.
+ • Generating derived sources in to the built products directory so they're saved along with the symroot.
+ • Switching to using .xcconfig files for maximum cleanliness.
+
+ * ANGLE.xcodeproj/project.pbxproj:
+ * Configurations/ANGLE.xcconfig: Added.
+ * Configurations/Base.xcconfig: Added.
+ * Configurations/DebugRelease.xcconfig: Added.
+
+2010-08-02 Paul Sawaya <psawaya@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ Add ANGLE library to WebKit. From the repository (http://angleproject.googlecode.com) as of July 22.
+ https://bugs.webkit.org/show_bug.cgi?id=42789
+
diff --git a/Source/ThirdParty/ANGLE/Configurations/ANGLE.xcconfig b/Source/ThirdParty/ANGLE/Configurations/ANGLE.xcconfig
new file mode 100644
index 000000000..644b71dda
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/Configurations/ANGLE.xcconfig
@@ -0,0 +1,5 @@
+PRODUCT_NAME = ANGLE;
+
+HEADER_SEARCH_PATHS = include src;
+INSTALL_PATH = /usr/local/lib;
+PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/ANGLE;
diff --git a/Source/ThirdParty/ANGLE/Configurations/Base.xcconfig b/Source/ThirdParty/ANGLE/Configurations/Base.xcconfig
new file mode 100644
index 000000000..4a84fb355
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/Configurations/Base.xcconfig
@@ -0,0 +1,47 @@
+#include "CompilerVersion.xcconfig"
+
+DEAD_CODE_STRIPPING = YES;
+DEBUG_INFORMATION_FORMAT = dwarf;
+GCC_C_LANGUAGE_STANDARD = gnu99;
+GCC_DEBUGGING_SYMBOLS = default;
+GCC_ENABLE_CPP_EXCEPTIONS = NO;
+GCC_ENABLE_CPP_RTTI = NO;
+GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+GCC_ENABLE_OBJC_GC = supported;
+GCC_ENABLE_SYMBOL_SEPARATION = NO;
+GCC_FAST_OBJC_DISPATCH = YES;
+GCC_MODEL_TUNING = G5;
+GCC_OBJC_CALL_CXX_CDTORS = YES;
+GCC_OPTIMIZATION_LEVEL = s;
+GCC_PRECOMPILE_PREFIX_HEADER = NO;
+GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+GCC_THREADSAFE_STATICS = NO;
+GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+LINKER_DISPLAYS_MANGLED_NAMES = YES;
+PREBINDING = NO;
+STRIP_INSTALLED_PRODUCT = NO;
+
+
+REAL_PLATFORM_NAME = $(REAL_PLATFORM_NAME_$(PLATFORM_NAME));
+REAL_PLATFORM_NAME_ = $(REAL_PLATFORM_NAME_macosx);
+REAL_PLATFORM_NAME_iphoneos = iphoneos;
+REAL_PLATFORM_NAME_iphonesimulator = iphonesimulator;
+REAL_PLATFORM_NAME_macosx = macosx;
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+// If the target Mac OS X version does not match the current Mac OS X version then we'll want to build using the target version's SDK.
+SDKROOT = $(SDKROOT_$(MAC_OS_X_VERSION_MAJOR)_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+SDKROOT_1060_1050 = macosx10.5;
+SDKROOT_1070_1050 = macosx10.5;
+SDKROOT_1080_1050 = macosx10.5;
+SDKROOT_1090_1050 = macosx10.5;
+SDKROOT_1070_1060 = macosx10.6;
+SDKROOT_1080_1060 = macosx10.6;
+SDKROOT_1090_1060 = macosx10.6;
+SDKROOT_1080_1070 = macosx10.7;
+SDKROOT_1090_1070 = macosx10.7;
+SDKROOT_1090_1080 = macosx10.8;
diff --git a/Source/ThirdParty/ANGLE/Configurations/CompilerVersion.xcconfig b/Source/ThirdParty/ANGLE/Configurations/CompilerVersion.xcconfig
new file mode 100644
index 000000000..a8c7f75a0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/Configurations/CompilerVersion.xcconfig
@@ -0,0 +1,84 @@
+// Copyright (C) 2009, 2010, 2011 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+IS_XCODE_0400 = $(IS_XCODE_0400_$(XCODE_VERSION_MINOR));
+IS_XCODE_0400_0400 = YES;
+
+IS_XCODE_0400_OR_0410 = $(IS_XCODE_0400_OR_0410_$(XCODE_VERSION_MINOR));
+IS_XCODE_0400_OR_0410_0400 = YES;
+IS_XCODE_0400_OR_0410_0410 = YES;
+
+// The version of the LLVM Compiler in Xcode 4.0 and earlier have difficulty compiling our code.
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS = $(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_$(XCODE_VERSION_MAJOR));
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_0300 = YES;
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_0400 = $(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_IS_XCODE_0400_$(IS_XCODE_0400));
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_IS_XCODE_0400_YES = YES;
+
+// The version of the LLVM Compiler in Xcode 4.1 and earlier do not generate fast enough code.
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS = $(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_$(XCODE_VERSION_MAJOR));
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_0300 = YES;
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_0400 = $(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_IS_XCODE_0400_OR_0410_$(IS_XCODE_0400_OR_0410));
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_IS_XCODE_0400_OR_0410_YES = YES;
+
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS = $(LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_$(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS));
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_ = YES;
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_YES = NO;
+
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS = $(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_$(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS));
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_ = YES;
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_YES = NO;
+
+
+// Use GCC 4.2 with Xcode 3.1, which includes GCC 4.2 but defaults to GCC 4.0.
+// Note that Xcode versions as new as 3.1.2 use XCODE_VERSION_ACTUAL for the minor version
+// number. Newer versions of Xcode use XCODE_VERSION_MINOR for the minor version, and
+// XCODE_VERSION_ACTUAL for the full version number.
+TARGET_GCC_VERSION = $(TARGET_GCC_VERSION_$(REAL_PLATFORM_NAME));
+TARGET_GCC_VERSION_iphoneos = LLVM_GCC_42;
+TARGET_GCC_VERSION_iphonesimulator = GCC_42;
+TARGET_GCC_VERSION_macosx = $(TARGET_GCC_VERSION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+
+TARGET_GCC_VERSION_macosx_1050 = $(TARGET_GCC_VERSION_macosx_1050_$(XCODE_VERSION_MINOR));
+TARGET_GCC_VERSION_macosx_1050_ = $(TARGET_GCC_VERSION_macosx_1050_$(XCODE_VERSION_ACTUAL));
+TARGET_GCC_VERSION_macosx_1050_0310 = GCC_42;
+TARGET_GCC_VERSION_macosx_1050_0320 = GCC_42;
+
+TARGET_GCC_VERSION_macosx_1060 = $(TARGET_GCC_VERSION_macosx_1060_AND_1070_$(CONFIGURATION));
+TARGET_GCC_VERSION_macosx_1070 = $(TARGET_GCC_VERSION_macosx_1060_AND_1070_$(CONFIGURATION));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Debug = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Release = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Production = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_NON_LLVM_FALLBACK = GCC_42;
+TARGET_GCC_VERSION_macosx_1070_NON_LLVM_FALLBACK = LLVM_GCC_42;
+
+TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_YES = LLVM_COMPILER;
+TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_NO = $(TARGET_GCC_VERSION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)_NON_LLVM_FALLBACK);
+
+TARGET_GCC_VERSION_macosx_1080 = LLVM_COMPILER;
+TARGET_GCC_VERSION_macosx_1090 = LLVM_COMPILER;
+
+GCC_VERSION = $(GCC_VERSION_$(TARGET_GCC_VERSION));
+GCC_VERSION_GCC_40 = 4.0;
+GCC_VERSION_GCC_42 = 4.2;
+GCC_VERSION_LLVM_GCC_42 = com.apple.compilers.llvmgcc42;
+GCC_VERSION_LLVM_COMPILER = com.apple.compilers.llvm.clang.1_0;
diff --git a/Source/ThirdParty/ANGLE/Configurations/DebugRelease.xcconfig b/Source/ThirdParty/ANGLE/Configurations/DebugRelease.xcconfig
new file mode 100644
index 000000000..0236d3517
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/Configurations/DebugRelease.xcconfig
@@ -0,0 +1,19 @@
+#include "Base.xcconfig"
+
+ARCHS = $(ARCHS_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+ARCHS_1050 = $(NATIVE_ARCH);
+ARCHS_1060 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1080 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1090 = $(ARCHS_STANDARD_32_64_BIT);
+
+ONLY_ACTIVE_ARCH = YES;
+
+MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+MACOSX_DEPLOYMENT_TARGET_1050 = 10.5;
+MACOSX_DEPLOYMENT_TARGET_1060 = 10.6;
+MACOSX_DEPLOYMENT_TARGET_1070 = 10.7;
+MACOSX_DEPLOYMENT_TARGET_1080 = 10.8;
+MACOSX_DEPLOYMENT_TARGET_1090 = 10.9;
+
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
diff --git a/Source/ThirdParty/ANGLE/Makefile b/Source/ThirdParty/ANGLE/Makefile
new file mode 100644
index 000000000..cb4c11a57
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/Makefile
@@ -0,0 +1 @@
+include ../Makefile.shared
diff --git a/Source/ThirdParty/ANGLE/include/EGL/egl.h b/Source/ThirdParty/ANGLE/include/EGL/egl.h
new file mode 100644
index 000000000..99ea342a4
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/include/EGL/egl.h
@@ -0,0 +1,329 @@
+/* -*- mode: c; tab-width: 8; -*- */
+/* vi: set sw=4 ts=8: */
+/* Reference version of egl.h for EGL 1.4.
+ * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $
+ */
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#ifndef __egl_h_
+#define __egl_h_
+
+/* All platform-dependent types and macro boilerplate (such as EGLAPI
+ * and EGLAPIENTRY) should go in eglplatform.h.
+ */
+#include <EGL/eglplatform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* EGL Types */
+/* EGLint is defined in eglplatform.h */
+typedef unsigned int EGLBoolean;
+typedef unsigned int EGLenum;
+typedef void *EGLConfig;
+typedef void *EGLContext;
+typedef void *EGLDisplay;
+typedef void *EGLSurface;
+typedef void *EGLClientBuffer;
+
+/* EGL Versioning */
+#define EGL_VERSION_1_0 1
+#define EGL_VERSION_1_1 1
+#define EGL_VERSION_1_2 1
+#define EGL_VERSION_1_3 1
+#define EGL_VERSION_1_4 1
+
+/* EGL Enumerants. Bitmasks and other exceptional cases aside, most
+ * enums are assigned unique values starting at 0x3000.
+ */
+
+/* EGL aliases */
+#define EGL_FALSE 0
+#define EGL_TRUE 1
+
+/* Out-of-band handle values */
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_SURFACE ((EGLSurface)0)
+
+/* Out-of-band attribute value */
+#define EGL_DONT_CARE ((EGLint)-1)
+
+/* Errors / GetError return values */
+#define EGL_SUCCESS 0x3000
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */
+
+/* Reserved 0x300F-0x301F for additional errors */
+
+/* Config attributes */
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_RED_SIZE 0x3024
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_LEVEL 0x3029
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_NONE 0x3038 /* Attrib list terminator */
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */
+#define EGL_CONFORMANT 0x3042
+
+/* Reserved 0x3041-0x304F for additional config attributes */
+
+/* Config attribute values */
+#define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */
+#define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */
+#define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */
+#define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */
+#define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */
+
+/* More config attribute values, for EGL_TEXTURE_FORMAT */
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_2D 0x305F
+
+/* Config attribute mask bits */
+#define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */
+
+#define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */
+
+/* QueryString targets */
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_EXTENSIONS 0x3055
+#define EGL_CLIENT_APIS 0x308D
+
+/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */
+#define EGL_HEIGHT 0x3056
+#define EGL_WIDTH 0x3057
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_TARGET 0x3081
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_VG_COLORSPACE 0x3087
+#define EGL_VG_ALPHA_FORMAT 0x3088
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_VERTICAL_RESOLUTION 0x3091
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_SWAP_BEHAVIOR 0x3093
+#define EGL_MULTISAMPLE_RESOLVE 0x3099
+
+/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_SINGLE_BUFFER 0x3085
+
+/* OpenVG color spaces */
+#define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */
+#define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */
+
+/* OpenVG alpha formats */
+#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */
+#define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */
+
+/* Constant scale factor by which fractional display resolutions &
+ * aspect ratio are scaled when queried as integer values.
+ */
+#define EGL_DISPLAY_SCALING 10000
+
+/* Unknown display resolution/aspect ratio */
+#define EGL_UNKNOWN ((EGLint)-1)
+
+/* Back buffer swap behaviors */
+#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */
+#define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */
+
+/* CreatePbufferFromClientBuffer buffer types */
+#define EGL_OPENVG_IMAGE 0x3096
+
+/* QueryContext targets */
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+
+/* CreateContext attributes */
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+
+/* Multisample resolution behaviors */
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */
+#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */
+
+/* BindAPI/QueryAPI targets */
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENVG_API 0x30A1
+#define EGL_OPENGL_API 0x30A2
+
+/* GetCurrentSurface targets */
+#define EGL_DRAW 0x3059
+#define EGL_READ 0x305A
+
+/* WaitNative engines */
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+
+/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */
+#define EGL_COLORSPACE EGL_VG_COLORSPACE
+#define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT
+#define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB
+#define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR
+#define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE
+#define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE
+
+/* EGL extensions must request enum blocks from the Khronos
+ * API Registrar, who maintains the enumerant registry. Submit
+ * a bug in Khronos Bugzilla against task "Registry".
+ */
+
+
+
+/* EGL Functions */
+
+EGLAPI EGLint EGLAPIENTRY eglGetError(void);
+
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);
+
+EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
+ EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+ EGLConfig *configs, EGLint config_size,
+ EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+ const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
+ EGLNativePixmapType pixmap,
+ const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
+ EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+ EGLConfig config, const EGLint *attrib_list);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+ EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval);
+
+
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config,
+ EGLContext share_context,
+ const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+ EGLSurface read, EGLContext ctx);
+
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
+ EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface,
+ EGLNativePixmapType target);
+
+/* This is a generic function pointer type, whose name indicates it must
+ * be cast to the proper type *and calling convention* before use.
+ */
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+
+/* Now, define eglGetProcAddress using the generic function ptr. type */
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
+ eglGetProcAddress(const char *procname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __egl_h_ */
diff --git a/Source/ThirdParty/ANGLE/include/EGL/eglext.h b/Source/ThirdParty/ANGLE/include/EGL/eglext.h
new file mode 100644
index 000000000..b650a500c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/include/EGL/eglext.h
@@ -0,0 +1,235 @@
+#ifndef __eglext_h_
+#define __eglext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#include <EGL/eglplatform.h>
+
+/*************************************************************/
+
+/* Header file version number */
+/* Current version at http://www.khronos.org/registry/egl/ */
+/* $Revision: 10795 $ on $Date: 2010-03-19 17:04:17 -0700 (Fri, 19 Mar 2010) $ */
+#define EGL_EGLEXT_VERSION 5
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */
+#endif
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */
+#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */
+#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */
+#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */
+#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */
+#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */
+#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */
+#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface);
+#endif
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */
+typedef void *EGLImageKHR;
+#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0)
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#endif
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_reusable_sync
+#define EGL_KHR_reusable_sync 1
+
+typedef void* EGLSyncKHR;
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+
+#define EGL_SYNC_STATUS_KHR 0x30F1
+#define EGL_SIGNALED_KHR 0x30F2
+#define EGL_UNSIGNALED_KHR 0x30F3
+#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5
+#define EGL_CONDITION_SATISFIED_KHR 0x30F6
+#define EGL_SYNC_TYPE_KHR 0x30F7
+#define EGL_SYNC_REUSABLE_KHR 0x30FA
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001 /* eglClientWaitSyncKHR <flags> bitfield */
+#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
+#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0)
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+/* Most interfaces defined by EGL_KHR_image_pixmap above */
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+/* Interfaces defined by EGL_KHR_image above */
+#endif
+
+#ifndef EGL_IMG_context_priority
+#define EGL_IMG_context_priority 1
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#endif
+
+#ifndef EGL_NV_coverage_sample
+#define EGL_NV_coverage_sample 1
+#define EGL_COVERAGE_BUFFERS_NV 0x30E0
+#define EGL_COVERAGE_SAMPLES_NV 0x30E1
+#endif
+
+#ifndef EGL_NV_depth_nonlinear
+#define EGL_NV_depth_nonlinear 1
+#define EGL_DEPTH_ENCODING_NV 0x30E2
+#define EGL_DEPTH_ENCODING_NONE_NV 0
+#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3
+#endif
+
+#ifndef EGL_NV_sync
+#define EGL_NV_sync 1
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
+#define EGL_SYNC_STATUS_NV 0x30E7
+#define EGL_SIGNALED_NV 0x30E8
+#define EGL_UNSIGNALED_NV 0x30E9
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001
+#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull
+#define EGL_ALREADY_SIGNALED_NV 0x30EA
+#define EGL_TIMEOUT_EXPIRED_NV 0x30EB
+#define EGL_CONDITION_SATISFIED_NV 0x30EC
+#define EGL_SYNC_TYPE_NV 0x30ED
+#define EGL_SYNC_CONDITION_NV 0x30EE
+#define EGL_SYNC_FENCE_NV 0x30EF
+#define EGL_NO_SYNC_NV ((EGLSyncNV)0)
+typedef void* EGLSyncNV;
+typedef unsigned long long EGLTimeNV;
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLSyncNV eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+EGLBoolean eglDestroySyncNV (EGLSyncNV sync);
+EGLBoolean eglFenceNV (EGLSyncNV sync);
+EGLint eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+EGLBoolean eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
+EGLBoolean eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif
+
+#ifndef EGL_ANGLE_query_surface_pointer
+#define EGL_ANGLE_query_surface_pointer 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+
+#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
+#define EGL_ANGLE_surface_d3d_texture_2d_share_handle
+#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Source/ThirdParty/ANGLE/include/EGL/eglplatform.h b/Source/ThirdParty/ANGLE/include/EGL/eglplatform.h
new file mode 100644
index 000000000..22e855f56
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/include/EGL/eglplatform.h
@@ -0,0 +1,110 @@
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions for egl.h
+ * $Revision: 9724 $ on $Date: 2009-12-02 02:05:33 -0800 (Wed, 02 Dec 2009) $
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "EGL" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#ifndef EGLAPIENTRY
+#define EGLAPIENTRY KHRONOS_APIENTRY
+#endif
+#define EGLAPIENTRYP EGLAPIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ */
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+typedef HDC EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+typedef HWND EGLNativeWindowType;
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativeWindowType;
+typedef void *EGLNativePixmapType;
+
+#elif defined(__unix__)
+
+/* X11 (tentative) */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap EGLNativePixmapType;
+typedef Window EGLNativeWindowType;
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType NativePixmapType;
+typedef EGLNativeWindowType NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other. While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+#endif /* __eglplatform_h */
diff --git a/Source/ThirdParty/ANGLE/include/GLES2/gl2.h b/Source/ThirdParty/ANGLE/include/GLES2/gl2.h
new file mode 100644
index 000000000..e1d3b87cc
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/include/GLES2/gl2.h
@@ -0,0 +1,621 @@
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
+
+#include <GLES2/gl2platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef char GLchar;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX 0x1901
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
diff --git a/Source/ThirdParty/ANGLE/include/GLES2/gl2ext.h b/Source/ThirdParty/ANGLE/include/GLES2/gl2ext.h
new file mode 100644
index 000000000..01844de4b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/include/GLES2/gl2ext.h
@@ -0,0 +1,831 @@
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 10798 $ on $Date:: 2010-03-19 17:34:30 -0700 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_UNSIGNED_INT 0x1405
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_TEXTURE_WRAP_R_OES 0x8072
+#define GL_TEXTURE_3D_OES 0x806F
+#define GL_TEXTURE_BINDING_3D_OES 0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
+#define GL_SAMPLER_3D_OES 0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
+#endif
+
+/* GL_OES_texture_float */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+/* GL_OES_texture_half_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_npot */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
+#define GL_INT_10_10_10_2_OES 0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD 0x8740
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_MIN_EXT 0x8007
+#define GL_MAX_EXT 0x8008
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_COLOR_EXT 0x1800
+#define GL_DEPTH_EXT 0x1801
+#define GL_STENCIL_EXT 0x1802
+#endif
+
+/* GL_EXT_multi_draw_arrays */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_BGRA_EXT 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_SGX_PROGRAM_BINARY_IMG 0x9130
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA_IMG 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_SGX_BINARY_IMG 0x8C0A
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_COVERAGE_COMPONENT_NV 0x8ED0
+#define GL_COVERAGE_COMPONENT4_NV 0x8ED1
+#define GL_COVERAGE_ATTACHMENT_NV 0x8ED2
+#define GL_COVERAGE_BUFFERS_NV 0x8ED3
+#define GL_COVERAGE_SAMPLES_NV 0x8ED4
+#define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5
+#define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6
+#define GL_COVERAGE_AUTOMATIC_NV 0x8ED7
+#define GL_COVERAGE_BUFFER_BIT_NV 0x8000
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_TEXTURE_WIDTH_QCOM 0x8BD2
+#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3
+#define GL_TEXTURE_DEPTH_QCOM 0x8BD4
+#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5
+#define GL_TEXTURE_FORMAT_QCOM 0x8BD6
+#define GL_TEXTURE_TYPE_QCOM 0x8BD7
+#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8
+#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9
+#define GL_TEXTURE_TARGET_QCOM 0x8BDA
+#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB
+#define GL_STATE_RESTORE 0x8BDC
+#endif
+
+/* GL_QCOM_extended_get2 */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_WRITEONLY_RENDERING_QCOM 0x8823
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
+#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002
+#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004
+#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008
+#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010
+#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020
+#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040
+#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080
+#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100
+#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200
+#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400
+#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800
+#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000
+#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000
+#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000
+#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
+#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000
+#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000
+#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000
+#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000
+#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000
+#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000
+#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000
+#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000
+#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000
+#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000
+#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000
+#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000
+#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000
+#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000
+#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000
+#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6 // alias GL_FRAMEBUFFER_BINDING
+#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56
+#define GL_MAX_SAMPLES_ANGLE 0x8D57
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 1
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 1
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 1
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 1
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 1
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 1
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 1
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_OES_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array);
+GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
+GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
+GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_EXT_discard_framebuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_EXT_read_format_bgra 1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_IMG_program_binary 1
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_IMG_shader_binary 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_NV_coverage_sample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
+GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
+typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_NV_depth_nonlinear 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_QCOM_extended_get 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
+GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
+#endif
+
+/* GL_QCOM_extended_get2 */
+#ifndef GL_QCOM_extended_get2
+#define GL_QCOM_extended_get2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
+GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 1
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_QCOM_writeonly_rendering 1
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_QCOM_tiled_rendering 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
+#endif
+typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_ANGLE_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_ANGLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat,
+ GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat,
+ GLsizei width, GLsizei height);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/Source/ThirdParty/ANGLE/include/GLES2/gl2platform.h b/Source/ThirdParty/ANGLE/include/GLES2/gl2platform.h
new file mode 100644
index 000000000..c9fa3c4d6
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/include/GLES2/gl2platform.h
@@ -0,0 +1,30 @@
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY KHRONOS_APIENTRY
+#endif
+
+#endif /* __gl2platform_h_ */
diff --git a/Source/ThirdParty/ANGLE/include/GLSLANG/ShaderLang.h b/Source/ThirdParty/ANGLE/include/GLSLANG/ShaderLang.h
new file mode 100644
index 000000000..6fe688c75
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/include/GLSLANG/ShaderLang.h
@@ -0,0 +1,284 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef _COMPILER_INTERFACE_INCLUDED_
+#define _COMPILER_INTERFACE_INCLUDED_
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler.
+//
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Version number for shader translation API.
+// It is incremented everytime the API changes.
+#define SH_VERSION 105
+
+//
+// The names of the following enums have been derived by replacing GL prefix
+// with SH. For example, SH_INFO_LOG_LENGTH is equivalent to GL_INFO_LOG_LENGTH.
+// The enum values are also equal to the values of their GL counterpart. This
+// is done to make it easier for applications to use the shader library.
+//
+typedef enum {
+ SH_FRAGMENT_SHADER = 0x8B30,
+ SH_VERTEX_SHADER = 0x8B31
+} ShShaderType;
+
+typedef enum {
+ SH_GLES2_SPEC = 0x8B40,
+ SH_WEBGL_SPEC = 0x8B41
+} ShShaderSpec;
+
+typedef enum {
+ SH_ESSL_OUTPUT = 0x8B45,
+ SH_GLSL_OUTPUT = 0x8B46,
+ SH_HLSL_OUTPUT = 0x8B47
+} ShShaderOutput;
+
+typedef enum {
+ SH_NONE = 0,
+ SH_INT = 0x1404,
+ SH_FLOAT = 0x1406,
+ SH_FLOAT_VEC2 = 0x8B50,
+ SH_FLOAT_VEC3 = 0x8B51,
+ SH_FLOAT_VEC4 = 0x8B52,
+ SH_INT_VEC2 = 0x8B53,
+ SH_INT_VEC3 = 0x8B54,
+ SH_INT_VEC4 = 0x8B55,
+ SH_BOOL = 0x8B56,
+ SH_BOOL_VEC2 = 0x8B57,
+ SH_BOOL_VEC3 = 0x8B58,
+ SH_BOOL_VEC4 = 0x8B59,
+ SH_FLOAT_MAT2 = 0x8B5A,
+ SH_FLOAT_MAT3 = 0x8B5B,
+ SH_FLOAT_MAT4 = 0x8B5C,
+ SH_SAMPLER_2D = 0x8B5E,
+ SH_SAMPLER_CUBE = 0x8B60
+} ShDataType;
+
+typedef enum {
+ SH_INFO_LOG_LENGTH = 0x8B84,
+ SH_OBJECT_CODE_LENGTH = 0x8B88, // GL_SHADER_SOURCE_LENGTH
+ SH_ACTIVE_UNIFORMS = 0x8B86,
+ SH_ACTIVE_UNIFORM_MAX_LENGTH = 0x8B87,
+ SH_ACTIVE_ATTRIBUTES = 0x8B89,
+ SH_ACTIVE_ATTRIBUTE_MAX_LENGTH = 0x8B8A,
+ SH_MAPPED_NAME_MAX_LENGTH = 0x8B8B
+} ShShaderInfo;
+
+// Compile options.
+typedef enum {
+ SH_VALIDATE = 0,
+ SH_VALIDATE_LOOP_INDEXING = 0x0001,
+ SH_INTERMEDIATE_TREE = 0x0002,
+ SH_OBJECT_CODE = 0x0004,
+ SH_ATTRIBUTES_UNIFORMS = 0x0008,
+ SH_LINE_DIRECTIVES = 0x0010,
+ SH_SOURCE_PATH = 0x0020,
+ SH_MAP_LONG_VARIABLE_NAMES = 0x0040
+} ShCompileOptions;
+
+//
+// Driver must call this first, once, before doing any other
+// compiler operations.
+// If the function succeeds, the return value is nonzero, else zero.
+//
+int ShInitialize();
+//
+// Driver should call this at shutdown.
+// If the function succeeds, the return value is nonzero, else zero.
+//
+int ShFinalize();
+
+//
+// Implementation dependent built-in resources (constants and extensions).
+// The names for these resources has been obtained by stripping gl_/GL_.
+//
+typedef struct
+{
+ // Constants.
+ int MaxVertexAttribs;
+ int MaxVertexUniformVectors;
+ int MaxVaryingVectors;
+ int MaxVertexTextureImageUnits;
+ int MaxCombinedTextureImageUnits;
+ int MaxTextureImageUnits;
+ int MaxFragmentUniformVectors;
+ int MaxDrawBuffers;
+
+ // Extensions.
+ // Set to 1 to enable the extension, else 0.
+ int OES_standard_derivatives;
+} ShBuiltInResources;
+
+//
+// Initialize built-in resources with minimum expected values.
+//
+void ShInitBuiltInResources(ShBuiltInResources* resources);
+
+//
+// ShHandle held by but opaque to the driver. It is allocated,
+// managed, and de-allocated by the compiler. It's contents
+// are defined by and used by the compiler.
+//
+// If handle creation fails, 0 will be returned.
+//
+typedef void* ShHandle;
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+// Returns the handle of constructed compiler, null if the requested compiler is
+// not supported.
+// Parameters:
+// type: Specifies the type of shader - SH_FRAGMENT_SHADER or SH_VERTEX_SHADER.
+// spec: Specifies the language spec the compiler must conform to -
+// SH_GLES2_SPEC or SH_WEBGL_SPEC.
+// output: Specifies the output code type - SH_ESSL_OUTPUT, SH_GLSL_OUTPUT,
+// or SH_HLSL_OUTPUT.
+// resources: Specifies the built-in resources.
+ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
+ ShShaderOutput output,
+ const ShBuiltInResources* resources);
+void ShDestruct(ShHandle handle);
+
+//
+// Compiles the given shader source.
+// If the function succeeds, the return value is nonzero, else zero.
+// Parameters:
+// handle: Specifies the handle of compiler to be used.
+// shaderStrings: Specifies an array of pointers to null-terminated strings
+// containing the shader source code.
+// numStrings: Specifies the number of elements in shaderStrings array.
+// compileOptions: A mask containing the following parameters:
+// SH_VALIDATE: Validates shader to ensure that it conforms to the spec
+// specified during compiler construction.
+// SH_VALIDATE_LOOP_INDEXING: Validates loop and indexing in the shader to
+// ensure that they do not exceed the minimum
+// functionality mandated in GLSL 1.0 spec,
+// Appendix A, Section 4 and 5.
+// There is no need to specify this parameter when
+// compiling for WebGL - it is implied.
+// SH_INTERMEDIATE_TREE: Writes intermediate tree to info log.
+// Can be queried by calling ShGetInfoLog().
+// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader.
+// Can be queried by calling ShGetObjectCode().
+// SH_ATTRIBUTES_UNIFORMS: Extracts attributes and uniforms.
+// Can be queried by calling ShGetActiveAttrib() and
+// ShGetActiveUniform().
+//
+int ShCompile(
+ const ShHandle handle,
+ const char* const shaderStrings[],
+ const int numStrings,
+ int compileOptions
+ );
+
+// Returns a parameter from a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+// pname: Specifies the parameter to query.
+// The following parameters are defined:
+// SH_INFO_LOG_LENGTH: the number of characters in the information log
+// including the null termination character.
+// SH_OBJECT_CODE_LENGTH: the number of characters in the object code
+// including the null termination character.
+// SH_ACTIVE_ATTRIBUTES: the number of active attribute variables.
+// SH_ACTIVE_ATTRIBUTE_MAX_LENGTH: the length of the longest active attribute
+// variable name including the null
+// termination character.
+// SH_ACTIVE_UNIFORMS: the number of active uniform variables.
+// SH_ACTIVE_UNIFORM_MAX_LENGTH: the length of the longest active uniform
+// variable name including the null
+// termination character.
+// SH_MAPPED_NAME_MAX_LENGTH: the length of the mapped variable name including
+// the null termination character.
+//
+// params: Requested parameter
+void ShGetInfo(const ShHandle handle, ShShaderInfo pname, int* params);
+
+// Returns nul-terminated information log for a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+// infoLog: Specifies an array of characters that is used to return
+// the information log. It is assumed that infoLog has enough memory
+// to accomodate the information log. The size of the buffer required
+// to store the returned information log can be obtained by calling
+// ShGetInfo with SH_INFO_LOG_LENGTH.
+void ShGetInfoLog(const ShHandle handle, char* infoLog);
+
+// Returns null-terminated object code for a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+// infoLog: Specifies an array of characters that is used to return
+// the object code. It is assumed that infoLog has enough memory to
+// accomodate the object code. The size of the buffer required to
+// store the returned object code can be obtained by calling
+// ShGetInfo with SH_OBJECT_CODE_LENGTH.
+void ShGetObjectCode(const ShHandle handle, char* objCode);
+
+// Returns information about an active attribute variable.
+// Parameters:
+// handle: Specifies the compiler
+// index: Specifies the index of the attribute variable to be queried.
+// length: Returns the number of characters actually written in the string
+// indicated by name (excluding the null terminator) if a value other
+// than NULL is passed.
+// size: Returns the size of the attribute variable.
+// type: Returns the data type of the attribute variable.
+// name: Returns a null terminated string containing the name of the
+// attribute variable. It is assumed that name has enough memory to
+// accomodate the attribute variable name. The size of the buffer
+// required to store the attribute variable name can be obtained by
+// calling ShGetInfo with SH_ACTIVE_ATTRIBUTE_MAX_LENGTH.
+// mappedName: Returns a null terminated string containing the mapped name of
+// the attribute variable, It is assumed that mappedName has enough
+// memory (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care
+// about the mapped name. If the name is not mapped, then name and
+// mappedName are the same.
+void ShGetActiveAttrib(const ShHandle handle,
+ int index,
+ int* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName);
+
+// Returns information about an active uniform variable.
+// Parameters:
+// handle: Specifies the compiler
+// index: Specifies the index of the uniform variable to be queried.
+// length: Returns the number of characters actually written in the string
+// indicated by name (excluding the null terminator) if a value
+// other than NULL is passed.
+// size: Returns the size of the uniform variable.
+// type: Returns the data type of the uniform variable.
+// name: Returns a null terminated string containing the name of the
+// uniform variable. It is assumed that name has enough memory to
+// accomodate the uniform variable name. The size of the buffer required
+// to store the uniform variable name can be obtained by calling
+// ShGetInfo with SH_ACTIVE_UNIFORMS_MAX_LENGTH.
+// mappedName: Returns a null terminated string containing the mapped name of
+// the uniform variable, It is assumed that mappedName has enough
+// memory (SH_MAPPED_NAME_MAX_LENGTH), or NULL if don't care
+// about the mapped name. If the name is not mapped, then name and
+// mappedName are the same.
+void ShGetActiveUniform(const ShHandle handle,
+ int index,
+ int* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _COMPILER_INTERFACE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/include/KHR/khrplatform.h b/Source/ThirdParty/ANGLE/include/KHR/khrplatform.h
new file mode 100644
index 000000000..8ec0d199f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/include/KHR/khrplatform.h
@@ -0,0 +1,269 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ * http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ * #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ * khronos_int8_t signed 8 bit
+ * khronos_uint8_t unsigned 8 bit
+ * khronos_int16_t signed 16 bit
+ * khronos_uint16_t unsigned 16 bit
+ * khronos_int32_t signed 32 bit
+ * khronos_uint32_t unsigned 32 bit
+ * khronos_int64_t signed 64 bit
+ * khronos_uint64_t unsigned 64 bit
+ * khronos_intptr_t signed same number of bits as a pointer
+ * khronos_uintptr_t unsigned same number of bits as a pointer
+ * khronos_ssize_t signed size
+ * khronos_usize_t unsigned size
+ * khronos_float_t signed 32 bit floating point
+ * khronos_time_ns_t unsigned 64 bit time in nanoseconds
+ * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ * nanoseconds
+ * khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ * khronos_boolean_enum_t enumerated boolean type. This should
+ * only be used as a base type when a client API's boolean type is
+ * an enum. Client APIs which use an integer or other type for
+ * booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ * KHRONOS_APICALL
+ * KHRONOS_APIENTRY
+ * KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ * int arg1,
+ * int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+ /* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time. Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted). The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years. Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true. Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+ KHRONOS_FALSE = 0,
+ KHRONOS_TRUE = 1,
+ KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
diff --git a/Source/ThirdParty/ANGLE/src/build_angle.xcodeproj/project.pbxproj b/Source/ThirdParty/ANGLE/src/build_angle.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..409b62278
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/build_angle.xcodeproj/project.pbxproj
@@ -0,0 +1,687 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 1563D9916BFDAD853032CE1A /* All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 77CEFB7B40F05B0A804E6B2B /* Build configuration list for PBXAggregateTarget "All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ A15E78BECDFF20BC3FFF040A /* PBXTargetDependency */,
+ BA246CA19435A9FA8AC69146 /* PBXTargetDependency */,
+ E4A3D33CA49D013550B8BA5F /* PBXTargetDependency */,
+ );
+ name = All;
+ productName = All;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 05563ADFEA15116D7233332F /* QualifierAlive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4857E18799D332C30EF460C7 /* QualifierAlive.cpp */; };
+ 08A7933BD2F78A86B90200F6 /* Compiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0A118E5003E5C0E253C53839 /* Compiler.cpp */; };
+ 0A216949103E1E228F9C12F0 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 60C3998C9CE66DE0C5B0FD99 /* InitializeDll.cpp */; };
+ 0AC1897E461A0D4758E3DCE3 /* VersionGLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F727AEC906712EC238041464 /* VersionGLSL.cpp */; };
+ 0E9456F464E16392D1CCD030 /* ValidateLimitations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B148D967B8D288A8267BFF3A /* ValidateLimitations.cpp */; };
+ 0EC09B3B254829F8F1D952D3 /* ForLoopUnroll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5DC9B647E10F65F66142ECC1 /* ForLoopUnroll.cpp */; };
+ 1ED1D2C7C74C6B625AFB1CCF /* VariableInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 27C11EE10FED2979931FFC11 /* VariableInfo.cpp */; };
+ 296466566D8C0F023A553760 /* SearchSymbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 228A6DEDDF08DB370394A7AD /* SearchSymbol.cpp */; };
+ 2E7C0D3804B8308A493D9B4B /* glslang_tab.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F68A6AA811495718A6938C0 /* glslang_tab.cpp */; };
+ 3021E0BF1BC8442FF1F2F2B4 /* glslang_lex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 73A57C6D413773AEBA3C47A6 /* glslang_lex.cpp */; };
+ 3065D29E97FAC6E127388D15 /* Initialize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A54F2ED0D82D7BBCA4E9EEEA /* Initialize.cpp */; };
+ 32B1DBCD6B83F2146D787A62 /* atom.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C9B4616A65A5ABEF91FD6DC /* atom.c */; };
+ 35BE1BBEE6135A1CB0608EA8 /* cppstruct.c in Sources */ = {isa = PBXBuildFile; fileRef = 8058A0A2A0A02386867517EA /* cppstruct.c */; };
+ 3A96E9CAC8A25AF1564B652C /* memory.c in Sources */ = {isa = PBXBuildFile; fileRef = 294F442A2606FEC55F12A28E /* memory.c */; };
+ 3F18389BCB89370A930667F4 /* TranslatorGLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6FB70DC74A21FBCD665ABDF9 /* TranslatorGLSL.cpp */; };
+ 40FC189B8A246EDF14C2FDE3 /* intermOut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEAF6F3126C2EC4397785C3F /* intermOut.cpp */; };
+ 4B4BDE7AD6266B39ED43C2D4 /* CodeGenHLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C49549DCCAF450EB761520E1 /* CodeGenHLSL.cpp */; };
+ 50DF00005CC4212F6FB1291D /* Intermediate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3F7C486C370A72938FE8160F /* Intermediate.cpp */; };
+ 55CBD87573B803A173AC9129 /* util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3EE7215A7AB4EF71C97D2545 /* util.cpp */; };
+ 5F7B52A54DCE8155ED94ECF8 /* OutputHLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A5B5BB2526802479E19F993 /* OutputHLSL.cpp */; };
+ 6F9F875017A68ABE5D39FF19 /* ParseHelper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 976C831A75EBE009A9861796 /* ParseHelper.cpp */; };
+ 888F1382498E2D74AF2801C8 /* debug.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4ABA230FEA3654B030E4C4FB /* debug.cpp */; };
+ 896B720BD21F6749A7D83F30 /* MapLongVariableNames.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57CF1F83E842901C42D44825 /* MapLongVariableNames.cpp */; };
+ 93A41AF036E5EF87B366B563 /* TranslatorESSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0A3A260F5379A7E2655D40F3 /* TranslatorESSL.cpp */; };
+ 9886BCD5D0DD69B6FDE09DD8 /* UnfoldSelect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E3711A48A0BF16B1CBD77AC9 /* UnfoldSelect.cpp */; };
+ 9B111B83FB636FD5CDEC32A0 /* OutputGLSLBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCDF01F002ADE9DB8A3EF4FE /* OutputGLSLBase.cpp */; };
+ 9E8DFE1CCEF038BF2B65428C /* parseConst.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D2C9C8EB4A7EFF5B67FF9DBF /* parseConst.cpp */; };
+ AC23F58FDD3C55F5CA18EED7 /* RemoveTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B436EFF06913FCB19C3522A7 /* RemoveTree.cpp */; };
+ AD85517F086FDCEF3947C403 /* symbols.c in Sources */ = {isa = PBXBuildFile; fileRef = F013A7240BDAE8A61413D8C0 /* symbols.c */; };
+ B4858417E54365BE8CDE3919 /* ossource_posix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE258486005F6696CC031622 /* ossource_posix.cpp */; };
+ B8BD2685A16B188CCDFB052B /* ShaderLang.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56C7E99BA500A84C35216FE0 /* ShaderLang.cpp */; };
+ BEBBF4F0819EA3D03977A8FC /* InfoSink.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6E6927BE5D3C2C82F86111DF /* InfoSink.cpp */; };
+ C4AAB2BB4594C0DA318DCB1C /* OutputESSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DB2917C5B624712364DE4A75 /* OutputESSL.cpp */; };
+ C75EB9292A0DDA45592A8ACF /* OutputGLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 48B7402CC07A059FEF5EC351 /* OutputGLSL.cpp */; };
+ CB7F0EF0D6A89FA8C4DF5513 /* cpp.c in Sources */ = {isa = PBXBuildFile; fileRef = B75707B393B7EAB7DD9999CB /* cpp.c */; };
+ D56F7D00E9B162E416D37DF0 /* CodeGenGLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B7B1127C75B576FC00D74AED /* CodeGenGLSL.cpp */; };
+ E1C7C5DFF0B2DFEC09387F4E /* PoolAlloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B64EABE738FC666A5E4E2F42 /* PoolAlloc.cpp */; };
+ E8C727AA8E9DC5E7B58857DF /* tokens.c in Sources */ = {isa = PBXBuildFile; fileRef = 2D00745DA9914FDE274D03D5 /* tokens.c */; };
+ E99D6D80DBF05ECE7108B26D /* TranslatorHLSL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C3DAFF6BF12BB7F4784D6C7E /* TranslatorHLSL.cpp */; };
+ F098F463EDABCF0769007678 /* scanner.c in Sources */ = {isa = PBXBuildFile; fileRef = FF3AA694DF9A4455A813234D /* scanner.c */; };
+ F5AE2A292DFAF8C158412AA2 /* IntermTraverse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C4FE988EF9A293867E5C771B /* IntermTraverse.cpp */; };
+ F6ABD58F8CAB7641D8BFE935 /* SymbolTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B7E5B0F04635E6090F0DE8EF /* SymbolTable.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 1F7242496103EDF29CC25D87 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = DA188D8C6BF8073122539131 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = A838E9574B3FF14791DBDAB1;
+ remoteInfo = translator_hlsl;
+ };
+ 55D5F9BF727E4A3B6637802B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = DA188D8C6BF8073122539131 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 6F4FD35CB3DFC89D70ECD432;
+ remoteInfo = translator_common;
+ };
+ 60D3546AC27B094D6CA04CD6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = DA188D8C6BF8073122539131 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5892C7A3695330437AFE5714;
+ remoteInfo = translator_glsl;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 056FEADC7D95C6D4C9CF1113 /* scanner.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = scanner.h; sourceTree = "<group>"; };
+ 0A118E5003E5C0E253C53839 /* Compiler.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Compiler.cpp; sourceTree = "<group>"; };
+ 0A3A260F5379A7E2655D40F3 /* TranslatorESSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorESSL.cpp; sourceTree = "<group>"; };
+ 0C9B4616A65A5ABEF91FD6DC /* atom.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = atom.c; sourceTree = "<group>"; };
+ 120AD0A3B7642FB5A9AE3A56 /* VersionGLSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VersionGLSL.h; sourceTree = "<group>"; };
+ 12EAF028311EEA4753E82818 /* PoolAlloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PoolAlloc.h; sourceTree = "<group>"; };
+ 153BF06BF12C6F50496C6156 /* localintermediate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = localintermediate.h; sourceTree = "<group>"; };
+ 182BAD50D4E58B884F5EB9F3 /* ForLoopUnroll.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ForLoopUnroll.h; sourceTree = "<group>"; };
+ 228A6DEDDF08DB370394A7AD /* SearchSymbol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SearchSymbol.cpp; sourceTree = "<group>"; };
+ 27C11EE10FED2979931FFC11 /* VariableInfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VariableInfo.cpp; sourceTree = "<group>"; };
+ 27E4C7ED0B82E18DCBEDF1C9 /* BaseTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BaseTypes.h; sourceTree = "<group>"; };
+ 294F442A2606FEC55F12A28E /* memory.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = memory.c; sourceTree = "<group>"; };
+ 2A765B86CBAF0D4A3E69DCA7 /* UnfoldSelect.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UnfoldSelect.h; sourceTree = "<group>"; };
+ 2D00745DA9914FDE274D03D5 /* tokens.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tokens.c; sourceTree = "<group>"; };
+ 2E7C9B6E6DB751E12A2F6CB6 /* InitializeGlobals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InitializeGlobals.h; sourceTree = "<group>"; };
+ 3DDDC77216202A4DE1808BDB /* libtranslator_common.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtranslator_common.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3EE7215A7AB4EF71C97D2545 /* util.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = util.cpp; sourceTree = "<group>"; };
+ 3F68A6AA811495718A6938C0 /* glslang_tab.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = glslang_tab.cpp; sourceTree = "<group>"; };
+ 3F7C486C370A72938FE8160F /* Intermediate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Intermediate.cpp; sourceTree = "<group>"; };
+ 4857E18799D332C30EF460C7 /* QualifierAlive.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = QualifierAlive.cpp; sourceTree = "<group>"; };
+ 48B7402CC07A059FEF5EC351 /* OutputGLSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OutputGLSL.cpp; sourceTree = "<group>"; };
+ 497C5C24EEF466FB4B50A259 /* glslang.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = glslang.h; sourceTree = "<group>"; };
+ 4ABA230FEA3654B030E4C4FB /* debug.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = debug.cpp; sourceTree = "<group>"; };
+ 4FCF32CB2D8A42C930A66B00 /* glslang_tab.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = glslang_tab.h; sourceTree = "<group>"; };
+ 528FF201839C6F233E26FFDA /* cpp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cpp.h; sourceTree = "<group>"; };
+ 56C7E99BA500A84C35216FE0 /* ShaderLang.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ShaderLang.cpp; sourceTree = "<group>"; };
+ 57CF1F83E842901C42D44825 /* MapLongVariableNames.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MapLongVariableNames.cpp; sourceTree = "<group>"; };
+ 580B2A31F7C51A59B40F11A3 /* compile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = compile.h; sourceTree = "<group>"; };
+ 5A21599C59BC1A75A7FABA34 /* OutputHLSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OutputHLSL.h; sourceTree = "<group>"; };
+ 5D99354C4D8187D384C81207 /* VariableInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VariableInfo.h; sourceTree = "<group>"; };
+ 5DC9B647E10F65F66142ECC1 /* ForLoopUnroll.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ForLoopUnroll.cpp; sourceTree = "<group>"; };
+ 60C3998C9CE66DE0C5B0FD99 /* InitializeDll.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeDll.cpp; sourceTree = "<group>"; };
+ 6BB66AB5873868E23675B6DB /* OutputESSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OutputESSL.h; sourceTree = "<group>"; };
+ 6BBC8224B9D8E234D117FA0C /* preprocess.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = preprocess.h; sourceTree = "<group>"; };
+ 6E6927BE5D3C2C82F86111DF /* InfoSink.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InfoSink.cpp; sourceTree = "<group>"; };
+ 6FB70DC74A21FBCD665ABDF9 /* TranslatorGLSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorGLSL.cpp; sourceTree = "<group>"; };
+ 73A57C6D413773AEBA3C47A6 /* glslang_lex.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = glslang_lex.cpp; sourceTree = "<group>"; };
+ 799DC9611EE2EA3BA7CF5477 /* intermediate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = intermediate.h; sourceTree = "<group>"; };
+ 7C6BB12AB099556CF379D78F /* SymbolTable.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SymbolTable.h; sourceTree = "<group>"; };
+ 7D9CF376DC5799B4C6B3331E /* symbols.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = symbols.h; sourceTree = "<group>"; };
+ 8058A0A2A0A02386867517EA /* cppstruct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cppstruct.c; sourceTree = "<group>"; };
+ 81CC4245A8E5AB5584D336F3 /* MapLongVariableNames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MapLongVariableNames.h; sourceTree = "<group>"; };
+ 831399DEE5DABA09570FB3E7 /* memory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = memory.h; sourceTree = "<group>"; };
+ 8513FAC699DB1558D1D49A48 /* Initialize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Initialize.h; sourceTree = "<group>"; };
+ 85845FFF5A8E63364308236D /* InitializeParseContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InitializeParseContext.h; sourceTree = "<group>"; };
+ 89A6F7B1AD3918E64DF76EB1 /* slglobals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = slglobals.h; sourceTree = "<group>"; };
+ 90254842D72975672C2E9A93 /* ValidateLimitations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ValidateLimitations.h; sourceTree = "<group>"; };
+ 93D61CB0BCE54E069D71F920 /* OutputGLSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OutputGLSL.h; sourceTree = "<group>"; };
+ 95276AA6B36FC1B1D913FCE4 /* debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = "<group>"; };
+ 976C831A75EBE009A9861796 /* ParseHelper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ParseHelper.cpp; sourceTree = "<group>"; };
+ 9A5B5BB2526802479E19F993 /* OutputHLSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OutputHLSL.cpp; sourceTree = "<group>"; };
+ 9CED3AFF1E61B45EE1005656 /* atom.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = atom.h; sourceTree = "<group>"; };
+ 9D47B1AC82E4EE859AC54243 /* QualifierAlive.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QualifierAlive.h; sourceTree = "<group>"; };
+ A0CE43631849276A31187C7B /* InitializeDll.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InitializeDll.h; sourceTree = "<group>"; };
+ A1644B00E9304C407FDC5F47 /* libtranslator_glsl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtranslator_glsl.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ A447F75F33DA4C4C123AC952 /* libtranslator_hlsl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtranslator_hlsl.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ A51C728B615B41E1D59E9902 /* util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
+ A54F2ED0D82D7BBCA4E9EEEA /* Initialize.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Initialize.cpp; sourceTree = "<group>"; };
+ AA53B6632C76F905DF08E564 /* Types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = "<group>"; };
+ AE65E139AE10DE9EFAD8D5B1 /* ShHandle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ShHandle.h; sourceTree = "<group>"; };
+ AE7674C52BDDDB28AF5FFD9F /* unistd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = unistd.h; sourceTree = "<group>"; };
+ B148D967B8D288A8267BFF3A /* ValidateLimitations.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ValidateLimitations.cpp; sourceTree = "<group>"; };
+ B2F5CA11EEA92DF2384EFD93 /* ConstantUnion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ConstantUnion.h; sourceTree = "<group>"; };
+ B436EFF06913FCB19C3522A7 /* RemoveTree.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RemoveTree.cpp; sourceTree = "<group>"; };
+ B55B359CF7E486DBC49BBF0A /* OutputGLSLBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OutputGLSLBase.h; sourceTree = "<group>"; };
+ B64EABE738FC666A5E4E2F42 /* PoolAlloc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PoolAlloc.cpp; sourceTree = "<group>"; };
+ B75707B393B7EAB7DD9999CB /* cpp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cpp.c; sourceTree = "<group>"; };
+ B7B1127C75B576FC00D74AED /* CodeGenGLSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGenGLSL.cpp; sourceTree = "<group>"; };
+ B7E5B0F04635E6090F0DE8EF /* SymbolTable.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SymbolTable.cpp; sourceTree = "<group>"; };
+ BCDF01F002ADE9DB8A3EF4FE /* OutputGLSLBase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OutputGLSLBase.cpp; sourceTree = "<group>"; };
+ BE258486005F6696CC031622 /* ossource_posix.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ossource_posix.cpp; sourceTree = "<group>"; };
+ C3DAFF6BF12BB7F4784D6C7E /* TranslatorHLSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TranslatorHLSL.cpp; sourceTree = "<group>"; };
+ C49549DCCAF450EB761520E1 /* CodeGenHLSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGenHLSL.cpp; sourceTree = "<group>"; };
+ C4FE988EF9A293867E5C771B /* IntermTraverse.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IntermTraverse.cpp; sourceTree = "<group>"; };
+ C8BD59BD7056FFC21373C50A /* osinclude.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = osinclude.h; sourceTree = "<group>"; };
+ CEE0C90DF6D504D1F3629711 /* ParseHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParseHelper.h; sourceTree = "<group>"; };
+ CF2B62E0820C831AF812D000 /* build_angle.gyp */ = {isa = PBXFileReference; lastKnownFileType = text; path = build_angle.gyp; sourceTree = "<group>"; };
+ CFD12C6E46EBE0839BBE52B5 /* parser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
+ D13C3693B9E40D37F2FAB34A /* tokens.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tokens.h; sourceTree = "<group>"; };
+ D2C9C8EB4A7EFF5B67FF9DBF /* parseConst.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = parseConst.cpp; sourceTree = "<group>"; };
+ D40F78CB9BA0C89921FA319D /* RemoveTree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RemoveTree.h; sourceTree = "<group>"; };
+ D53DDD0CDF15EE1DD01F1A20 /* TranslatorESSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TranslatorESSL.h; sourceTree = "<group>"; };
+ DB2917C5B624712364DE4A75 /* OutputESSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OutputESSL.cpp; sourceTree = "<group>"; };
+ DDD3B7E3B7B35A0B8469AB87 /* TranslatorGLSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TranslatorGLSL.h; sourceTree = "<group>"; };
+ DEAF6F3126C2EC4397785C3F /* intermOut.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = intermOut.cpp; sourceTree = "<group>"; };
+ DEEAFC618A3B33F1FBFE3536 /* MMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MMap.h; sourceTree = "<group>"; };
+ E3711A48A0BF16B1CBD77AC9 /* UnfoldSelect.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnfoldSelect.cpp; sourceTree = "<group>"; };
+ E3A29B6E9C21B67C25FF0D2B /* TranslatorHLSL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TranslatorHLSL.h; sourceTree = "<group>"; };
+ F013A7240BDAE8A61413D8C0 /* symbols.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = symbols.c; sourceTree = "<group>"; };
+ F3E09DC8E1BF5D2958AACEDE /* SearchSymbol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SearchSymbol.h; sourceTree = "<group>"; };
+ F727AEC906712EC238041464 /* VersionGLSL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VersionGLSL.cpp; sourceTree = "<group>"; };
+ F74618F18FE5448115017C44 /* Common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Common.h; sourceTree = "<group>"; };
+ F7B2971D4EB3836B94B7ECAF /* InfoSink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InfoSink.h; sourceTree = "<group>"; };
+ F99E737D3FFD30CA5E354150 /* common.gypi */ = {isa = PBXFileReference; lastKnownFileType = text; name = common.gypi; path = ../build/common.gypi; sourceTree = "<group>"; };
+ FF3AA694DF9A4455A813234D /* scanner.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = scanner.c; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ A5C994E74DB1E60338E7BC11 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ CA71CBA633EFC63166BEC9F3 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FE3679A0955B25EB7BF116E6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 0E8D65F584FDB84DAABD3969 /* preprocessor */ = {
+ isa = PBXGroup;
+ children = (
+ 0C9B4616A65A5ABEF91FD6DC /* atom.c */,
+ 9CED3AFF1E61B45EE1005656 /* atom.h */,
+ 580B2A31F7C51A59B40F11A3 /* compile.h */,
+ B75707B393B7EAB7DD9999CB /* cpp.c */,
+ 528FF201839C6F233E26FFDA /* cpp.h */,
+ 8058A0A2A0A02386867517EA /* cppstruct.c */,
+ 294F442A2606FEC55F12A28E /* memory.c */,
+ 831399DEE5DABA09570FB3E7 /* memory.h */,
+ CFD12C6E46EBE0839BBE52B5 /* parser.h */,
+ 6BBC8224B9D8E234D117FA0C /* preprocess.h */,
+ FF3AA694DF9A4455A813234D /* scanner.c */,
+ 056FEADC7D95C6D4C9CF1113 /* scanner.h */,
+ 89A6F7B1AD3918E64DF76EB1 /* slglobals.h */,
+ F013A7240BDAE8A61413D8C0 /* symbols.c */,
+ 7D9CF376DC5799B4C6B3331E /* symbols.h */,
+ 2D00745DA9914FDE274D03D5 /* tokens.c */,
+ D13C3693B9E40D37F2FAB34A /* tokens.h */,
+ );
+ path = preprocessor;
+ sourceTree = "<group>";
+ };
+ 196DB6AB006BB83503C7D786 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 0E8D65F584FDB84DAABD3969 /* preprocessor */,
+ 27E4C7ED0B82E18DCBEDF1C9 /* BaseTypes.h */,
+ B7B1127C75B576FC00D74AED /* CodeGenGLSL.cpp */,
+ C49549DCCAF450EB761520E1 /* CodeGenHLSL.cpp */,
+ F74618F18FE5448115017C44 /* Common.h */,
+ 0A118E5003E5C0E253C53839 /* Compiler.cpp */,
+ B2F5CA11EEA92DF2384EFD93 /* ConstantUnion.h */,
+ 5DC9B647E10F65F66142ECC1 /* ForLoopUnroll.cpp */,
+ 182BAD50D4E58B884F5EB9F3 /* ForLoopUnroll.h */,
+ 6E6927BE5D3C2C82F86111DF /* InfoSink.cpp */,
+ F7B2971D4EB3836B94B7ECAF /* InfoSink.h */,
+ A54F2ED0D82D7BBCA4E9EEEA /* Initialize.cpp */,
+ 8513FAC699DB1558D1D49A48 /* Initialize.h */,
+ 60C3998C9CE66DE0C5B0FD99 /* InitializeDll.cpp */,
+ A0CE43631849276A31187C7B /* InitializeDll.h */,
+ 2E7C9B6E6DB751E12A2F6CB6 /* InitializeGlobals.h */,
+ 85845FFF5A8E63364308236D /* InitializeParseContext.h */,
+ C4FE988EF9A293867E5C771B /* IntermTraverse.cpp */,
+ 3F7C486C370A72938FE8160F /* Intermediate.cpp */,
+ DEEAFC618A3B33F1FBFE3536 /* MMap.h */,
+ 57CF1F83E842901C42D44825 /* MapLongVariableNames.cpp */,
+ 81CC4245A8E5AB5584D336F3 /* MapLongVariableNames.h */,
+ DB2917C5B624712364DE4A75 /* OutputESSL.cpp */,
+ 6BB66AB5873868E23675B6DB /* OutputESSL.h */,
+ 48B7402CC07A059FEF5EC351 /* OutputGLSL.cpp */,
+ 93D61CB0BCE54E069D71F920 /* OutputGLSL.h */,
+ BCDF01F002ADE9DB8A3EF4FE /* OutputGLSLBase.cpp */,
+ B55B359CF7E486DBC49BBF0A /* OutputGLSLBase.h */,
+ 9A5B5BB2526802479E19F993 /* OutputHLSL.cpp */,
+ 5A21599C59BC1A75A7FABA34 /* OutputHLSL.h */,
+ 976C831A75EBE009A9861796 /* ParseHelper.cpp */,
+ CEE0C90DF6D504D1F3629711 /* ParseHelper.h */,
+ B64EABE738FC666A5E4E2F42 /* PoolAlloc.cpp */,
+ 12EAF028311EEA4753E82818 /* PoolAlloc.h */,
+ 4857E18799D332C30EF460C7 /* QualifierAlive.cpp */,
+ 9D47B1AC82E4EE859AC54243 /* QualifierAlive.h */,
+ B436EFF06913FCB19C3522A7 /* RemoveTree.cpp */,
+ D40F78CB9BA0C89921FA319D /* RemoveTree.h */,
+ 228A6DEDDF08DB370394A7AD /* SearchSymbol.cpp */,
+ F3E09DC8E1BF5D2958AACEDE /* SearchSymbol.h */,
+ AE65E139AE10DE9EFAD8D5B1 /* ShHandle.h */,
+ 56C7E99BA500A84C35216FE0 /* ShaderLang.cpp */,
+ B7E5B0F04635E6090F0DE8EF /* SymbolTable.cpp */,
+ 7C6BB12AB099556CF379D78F /* SymbolTable.h */,
+ 0A3A260F5379A7E2655D40F3 /* TranslatorESSL.cpp */,
+ D53DDD0CDF15EE1DD01F1A20 /* TranslatorESSL.h */,
+ 6FB70DC74A21FBCD665ABDF9 /* TranslatorGLSL.cpp */,
+ DDD3B7E3B7B35A0B8469AB87 /* TranslatorGLSL.h */,
+ C3DAFF6BF12BB7F4784D6C7E /* TranslatorHLSL.cpp */,
+ E3A29B6E9C21B67C25FF0D2B /* TranslatorHLSL.h */,
+ AA53B6632C76F905DF08E564 /* Types.h */,
+ E3711A48A0BF16B1CBD77AC9 /* UnfoldSelect.cpp */,
+ 2A765B86CBAF0D4A3E69DCA7 /* UnfoldSelect.h */,
+ B148D967B8D288A8267BFF3A /* ValidateLimitations.cpp */,
+ 90254842D72975672C2E9A93 /* ValidateLimitations.h */,
+ 27C11EE10FED2979931FFC11 /* VariableInfo.cpp */,
+ 5D99354C4D8187D384C81207 /* VariableInfo.h */,
+ F727AEC906712EC238041464 /* VersionGLSL.cpp */,
+ 120AD0A3B7642FB5A9AE3A56 /* VersionGLSL.h */,
+ 4ABA230FEA3654B030E4C4FB /* debug.cpp */,
+ 95276AA6B36FC1B1D913FCE4 /* debug.h */,
+ 497C5C24EEF466FB4B50A259 /* glslang.h */,
+ 73A57C6D413773AEBA3C47A6 /* glslang_lex.cpp */,
+ 3F68A6AA811495718A6938C0 /* glslang_tab.cpp */,
+ 4FCF32CB2D8A42C930A66B00 /* glslang_tab.h */,
+ DEAF6F3126C2EC4397785C3F /* intermOut.cpp */,
+ 799DC9611EE2EA3BA7CF5477 /* intermediate.h */,
+ 153BF06BF12C6F50496C6156 /* localintermediate.h */,
+ C8BD59BD7056FFC21373C50A /* osinclude.h */,
+ BE258486005F6696CC031622 /* ossource_posix.cpp */,
+ D2C9C8EB4A7EFF5B67FF9DBF /* parseConst.cpp */,
+ AE7674C52BDDDB28AF5FFD9F /* unistd.h */,
+ 3EE7215A7AB4EF71C97D2545 /* util.cpp */,
+ A51C728B615B41E1D59E9902 /* util.h */,
+ );
+ name = Source;
+ path = compiler;
+ sourceTree = "<group>";
+ };
+ 5BBEFF9B91738297B95C568D = {
+ isa = PBXGroup;
+ children = (
+ 196DB6AB006BB83503C7D786 /* Source */,
+ E0EDC4130E7D374318CE72BE /* Products */,
+ B2C184C3543198BA51592EA4 /* Build */,
+ );
+ sourceTree = "<group>";
+ };
+ B2C184C3543198BA51592EA4 /* Build */ = {
+ isa = PBXGroup;
+ children = (
+ CF2B62E0820C831AF812D000 /* build_angle.gyp */,
+ F99E737D3FFD30CA5E354150 /* common.gypi */,
+ );
+ name = Build;
+ sourceTree = "<group>";
+ };
+ E0EDC4130E7D374318CE72BE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 3DDDC77216202A4DE1808BDB /* libtranslator_common.a */,
+ A1644B00E9304C407FDC5F47 /* libtranslator_glsl.a */,
+ A447F75F33DA4C4C123AC952 /* libtranslator_hlsl.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 5892C7A3695330437AFE5714 /* translator_glsl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8B8815CA2EFE60FD0C0361BF /* Build configuration list for PBXNativeTarget "translator_glsl" */;
+ buildPhases = (
+ BABCE721106B5C1527EFEF0D /* Sources */,
+ CA71CBA633EFC63166BEC9F3 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = translator_glsl;
+ productName = translator_glsl;
+ productReference = A1644B00E9304C407FDC5F47 /* libtranslator_glsl.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 6F4FD35CB3DFC89D70ECD432 /* translator_common */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 34BB38E3A74418B2A063B49E /* Build configuration list for PBXNativeTarget "translator_common" */;
+ buildPhases = (
+ EAA22CA63FD572FCCB913D22 /* Sources */,
+ A5C994E74DB1E60338E7BC11 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = translator_common;
+ productName = translator_common;
+ productReference = 3DDDC77216202A4DE1808BDB /* libtranslator_common.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ A838E9574B3FF14791DBDAB1 /* translator_hlsl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C71E79C7829FD796CF621B44 /* Build configuration list for PBXNativeTarget "translator_hlsl" */;
+ buildPhases = (
+ 05F3BCA9518770BE3F1E0A38 /* Sources */,
+ FE3679A0955B25EB7BF116E6 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = translator_hlsl;
+ productName = translator_hlsl;
+ productReference = A447F75F33DA4C4C123AC952 /* libtranslator_hlsl.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ DA188D8C6BF8073122539131 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = YES;
+ };
+ buildConfigurationList = 0E59F8FE4A8099E8DDCA4CE7 /* Build configuration list for PBXProject "build_angle" */;
+ compatibilityVersion = "Xcode 3.1";
+ hasScannedForEncodings = 1;
+ mainGroup = 5BBEFF9B91738297B95C568D;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 1563D9916BFDAD853032CE1A /* All */,
+ 6F4FD35CB3DFC89D70ECD432 /* translator_common */,
+ 5892C7A3695330437AFE5714 /* translator_glsl */,
+ A838E9574B3FF14791DBDAB1 /* translator_hlsl */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 05F3BCA9518770BE3F1E0A38 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4B4BDE7AD6266B39ED43C2D4 /* CodeGenHLSL.cpp in Sources */,
+ 5F7B52A54DCE8155ED94ECF8 /* OutputHLSL.cpp in Sources */,
+ E99D6D80DBF05ECE7108B26D /* TranslatorHLSL.cpp in Sources */,
+ 9886BCD5D0DD69B6FDE09DD8 /* UnfoldSelect.cpp in Sources */,
+ 296466566D8C0F023A553760 /* SearchSymbol.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BABCE721106B5C1527EFEF0D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D56F7D00E9B162E416D37DF0 /* CodeGenGLSL.cpp in Sources */,
+ 0EC09B3B254829F8F1D952D3 /* ForLoopUnroll.cpp in Sources */,
+ C4AAB2BB4594C0DA318DCB1C /* OutputESSL.cpp in Sources */,
+ 9B111B83FB636FD5CDEC32A0 /* OutputGLSLBase.cpp in Sources */,
+ C75EB9292A0DDA45592A8ACF /* OutputGLSL.cpp in Sources */,
+ 93A41AF036E5EF87B366B563 /* TranslatorESSL.cpp in Sources */,
+ 3F18389BCB89370A930667F4 /* TranslatorGLSL.cpp in Sources */,
+ 0AC1897E461A0D4758E3DCE3 /* VersionGLSL.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ EAA22CA63FD572FCCB913D22 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 08A7933BD2F78A86B90200F6 /* Compiler.cpp in Sources */,
+ 888F1382498E2D74AF2801C8 /* debug.cpp in Sources */,
+ 3021E0BF1BC8442FF1F2F2B4 /* glslang_lex.cpp in Sources */,
+ 2E7C0D3804B8308A493D9B4B /* glslang_tab.cpp in Sources */,
+ BEBBF4F0819EA3D03977A8FC /* InfoSink.cpp in Sources */,
+ 3065D29E97FAC6E127388D15 /* Initialize.cpp in Sources */,
+ 0A216949103E1E228F9C12F0 /* InitializeDll.cpp in Sources */,
+ 50DF00005CC4212F6FB1291D /* Intermediate.cpp in Sources */,
+ 40FC189B8A246EDF14C2FDE3 /* intermOut.cpp in Sources */,
+ F5AE2A292DFAF8C158412AA2 /* IntermTraverse.cpp in Sources */,
+ 896B720BD21F6749A7D83F30 /* MapLongVariableNames.cpp in Sources */,
+ 9E8DFE1CCEF038BF2B65428C /* parseConst.cpp in Sources */,
+ 6F9F875017A68ABE5D39FF19 /* ParseHelper.cpp in Sources */,
+ E1C7C5DFF0B2DFEC09387F4E /* PoolAlloc.cpp in Sources */,
+ 05563ADFEA15116D7233332F /* QualifierAlive.cpp in Sources */,
+ AC23F58FDD3C55F5CA18EED7 /* RemoveTree.cpp in Sources */,
+ B8BD2685A16B188CCDFB052B /* ShaderLang.cpp in Sources */,
+ F6ABD58F8CAB7641D8BFE935 /* SymbolTable.cpp in Sources */,
+ 55CBD87573B803A173AC9129 /* util.cpp in Sources */,
+ 0E9456F464E16392D1CCD030 /* ValidateLimitations.cpp in Sources */,
+ 1ED1D2C7C74C6B625AFB1CCF /* VariableInfo.cpp in Sources */,
+ 32B1DBCD6B83F2146D787A62 /* atom.c in Sources */,
+ CB7F0EF0D6A89FA8C4DF5513 /* cpp.c in Sources */,
+ 35BE1BBEE6135A1CB0608EA8 /* cppstruct.c in Sources */,
+ 3A96E9CAC8A25AF1564B652C /* memory.c in Sources */,
+ F098F463EDABCF0769007678 /* scanner.c in Sources */,
+ AD85517F086FDCEF3947C403 /* symbols.c in Sources */,
+ E8C727AA8E9DC5E7B58857DF /* tokens.c in Sources */,
+ B4858417E54365BE8CDE3919 /* ossource_posix.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ A15E78BECDFF20BC3FFF040A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 6F4FD35CB3DFC89D70ECD432 /* translator_common */;
+ targetProxy = 55D5F9BF727E4A3B6637802B /* PBXContainerItemProxy */;
+ };
+ BA246CA19435A9FA8AC69146 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5892C7A3695330437AFE5714 /* translator_glsl */;
+ targetProxy = 60D3546AC27B094D6CA04CD6 /* PBXContainerItemProxy */;
+ };
+ E4A3D33CA49D013550B8BA5F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = A838E9574B3FF14791DBDAB1 /* translator_hlsl */;
+ targetProxy = 1F7242496103EDF29CC25D87 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 322A8C62423B595E11BAD42D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = All;
+ };
+ name = Debug;
+ };
+ 4DA42A78D3B855C9CD8F658D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "\"ANGLE_DISABLE_TRACE\"",
+ "\"ANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0\"",
+ );
+ HEADER_SEARCH_PATHS = (
+ .,
+ ../include,
+ );
+ PRODUCT_NAME = translator_common;
+ };
+ name = Release;
+ };
+ 4F851F5BA5FA43E9E0B9CB86 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = All;
+ };
+ name = Release;
+ };
+ 88ADC9285519A668808B51EE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "\"ANGLE_DISABLE_TRACE\"",
+ "\"ANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0\"",
+ );
+ HEADER_SEARCH_PATHS = (
+ .,
+ ../include,
+ );
+ PRODUCT_NAME = translator_glsl;
+ };
+ name = Debug;
+ };
+ 9DC66E1FF9349CDCC8D52C46 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INTERMEDIATE_DIR = "$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)";
+ SHARED_INTERMEDIATE_DIR = "$(SYMROOT)/DerivedSources/$(CONFIGURATION)";
+ };
+ name = Debug;
+ };
+ AF7C2CD10C6FEA076B141E6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "\"ANGLE_DISABLE_TRACE\"",
+ "\"ANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0\"",
+ );
+ HEADER_SEARCH_PATHS = (
+ .,
+ ../include,
+ );
+ PRODUCT_NAME = translator_glsl;
+ };
+ name = Release;
+ };
+ B096FAF032DB19AB637D38F0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "\"ANGLE_DISABLE_TRACE\"",
+ "\"ANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0\"",
+ );
+ HEADER_SEARCH_PATHS = (
+ .,
+ ../include,
+ );
+ PRODUCT_NAME = translator_hlsl;
+ };
+ name = Release;
+ };
+ C4546B14B0EB5EB8C5D39DC2 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INTERMEDIATE_DIR = "$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)";
+ SHARED_INTERMEDIATE_DIR = "$(SYMROOT)/DerivedSources/$(CONFIGURATION)";
+ };
+ name = Release;
+ };
+ F029E0D369FAFEA46BDAFCEE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "\"ANGLE_DISABLE_TRACE\"",
+ "\"ANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0\"",
+ );
+ HEADER_SEARCH_PATHS = (
+ .,
+ ../include,
+ );
+ PRODUCT_NAME = translator_hlsl;
+ };
+ name = Debug;
+ };
+ FF01CDF4594E0FF9E581B319 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "\"ANGLE_DISABLE_TRACE\"",
+ "\"ANGLE_COMPILE_OPTIMIZATION_LEVEL=D3DCOMPILE_OPTIMIZATION_LEVEL0\"",
+ );
+ HEADER_SEARCH_PATHS = (
+ .,
+ ../include,
+ );
+ PRODUCT_NAME = translator_common;
+ };
+ name = Debug;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 0E59F8FE4A8099E8DDCA4CE7 /* Build configuration list for PBXProject "build_angle" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 9DC66E1FF9349CDCC8D52C46 /* Debug */,
+ C4546B14B0EB5EB8C5D39DC2 /* Release */,
+ );
+ defaultConfigurationIsVisible = 1;
+ defaultConfigurationName = Debug;
+ };
+ 34BB38E3A74418B2A063B49E /* Build configuration list for PBXNativeTarget "translator_common" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FF01CDF4594E0FF9E581B319 /* Debug */,
+ 4DA42A78D3B855C9CD8F658D /* Release */,
+ );
+ defaultConfigurationIsVisible = 1;
+ defaultConfigurationName = Debug;
+ };
+ 77CEFB7B40F05B0A804E6B2B /* Build configuration list for PBXAggregateTarget "All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 322A8C62423B595E11BAD42D /* Debug */,
+ 4F851F5BA5FA43E9E0B9CB86 /* Release */,
+ );
+ defaultConfigurationIsVisible = 1;
+ defaultConfigurationName = Debug;
+ };
+ 8B8815CA2EFE60FD0C0361BF /* Build configuration list for PBXNativeTarget "translator_glsl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 88ADC9285519A668808B51EE /* Debug */,
+ AF7C2CD10C6FEA076B141E6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 1;
+ defaultConfigurationName = Debug;
+ };
+ C71E79C7829FD796CF621B44 /* Build configuration list for PBXNativeTarget "translator_hlsl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F029E0D369FAFEA46BDAFCEE /* Debug */,
+ B096FAF032DB19AB637D38F0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 1;
+ defaultConfigurationName = Debug;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = DA188D8C6BF8073122539131 /* Project object */;
+}
diff --git a/Source/ThirdParty/ANGLE/src/common/angleutils.h b/Source/ThirdParty/ANGLE/src/common/angleutils.h
new file mode 100644
index 000000000..24c766bdf
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/common/angleutils.h
@@ -0,0 +1,18 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// angleutils.h: Common ANGLE utilities.
+
+#ifndef COMMON_ANGLEUTILS_H_
+#define COMMON_ANGLEUTILS_H_
+
+// A macro to disallow the copy constructor and operator= functions
+// This must be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+#endif // COMMON_ANGLEUTILS_H_
diff --git a/Source/ThirdParty/ANGLE/src/common/debug.cpp b/Source/ThirdParty/ANGLE/src/common/debug.cpp
new file mode 100644
index 000000000..4dd7327e7
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/common/debug.cpp
@@ -0,0 +1,97 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// debug.cpp: Debugging utilities.
+
+#include "common/debug.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <d3d9.h>
+#include <windows.h>
+
+namespace gl
+{
+
+typedef void (WINAPI *PerfOutputFunction)(D3DCOLOR, LPCWSTR);
+
+static void output(bool traceFileDebugOnly, PerfOutputFunction perfFunc, const char *format, va_list vararg)
+{
+#if !defined(ANGLE_DISABLE_PERF)
+ if (perfActive())
+ {
+ char message[4096];
+ int len = vsprintf_s(message, format, vararg);
+ if (len < 0)
+ {
+ return;
+ }
+
+ // There are no ASCII variants of these D3DPERF functions.
+ wchar_t wideMessage[4096];
+ for (int i = 0; i < len; ++i)
+ {
+ wideMessage[i] = message[i];
+ }
+ wideMessage[len] = 0;
+
+ perfFunc(0, wideMessage);
+ }
+#endif
+
+#if !defined(ANGLE_DISABLE_TRACE)
+#if defined(NDEBUG)
+ if (traceFileDebugOnly)
+ {
+ return;
+ }
+#endif
+
+ FILE* file = fopen(TRACE_OUTPUT_FILE, "a");
+ if (file)
+ {
+ vfprintf(file, format, vararg);
+ fclose(file);
+ }
+#endif
+}
+
+void trace(bool traceFileDebugOnly, const char *format, ...)
+{
+ va_list vararg;
+ va_start(vararg, format);
+ output(traceFileDebugOnly, D3DPERF_SetMarker, format, vararg);
+ va_end(vararg);
+}
+
+bool perfActive()
+{
+#if defined(ANGLE_DISABLE_PERF)
+ return false;
+#else
+ static bool active = D3DPERF_GetStatus() != 0;
+ return active;
+#endif
+}
+
+ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...)
+{
+ va_list vararg;
+ va_start(vararg, format);
+ output(true, reinterpret_cast<PerfOutputFunction>(D3DPERF_BeginEvent), format, vararg);
+ va_end(vararg);
+}
+
+ScopedPerfEventHelper::~ScopedPerfEventHelper()
+{
+#if !defined(ANGLE_DISABLE_PERF)
+ if (perfActive())
+ {
+ D3DPERF_EndEvent();
+ }
+#endif
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/common/debug.h b/Source/ThirdParty/ANGLE/src/common/debug.h
new file mode 100644
index 000000000..9828ecf03
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/common/debug.h
@@ -0,0 +1,103 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// debug.h: Debugging utilities.
+
+#ifndef COMMON_DEBUG_H_
+#define COMMON_DEBUG_H_
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "common/angleutils.h"
+
+#if !defined(TRACE_OUTPUT_FILE)
+#define TRACE_OUTPUT_FILE "debug.txt"
+#endif
+
+namespace gl
+{
+ // Outputs text to the debugging log
+ void trace(bool traceFileDebugOnly, const char *format, ...);
+
+ // Returns whether D3DPERF is active.
+ bool perfActive();
+
+ // Pairs a D3D begin event with an end event.
+ class ScopedPerfEventHelper
+ {
+ public:
+ ScopedPerfEventHelper(const char* format, ...);
+ ~ScopedPerfEventHelper();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedPerfEventHelper);
+ };
+}
+
+// A macro to output a trace of a function call and its arguments to the debugging log
+#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF)
+#define TRACE(message, ...) (void(0))
+#else
+#define TRACE(message, ...) gl::trace(true, "trace: %s(%d): "message"\n", __FUNCTION__, __LINE__, __VA_ARGS__)
+#endif
+
+// A macro to output a function call and its arguments to the debugging log, to denote an item in need of fixing.
+#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF)
+#define FIXME(message, ...) (void(0))
+#else
+#define FIXME(message, ...) gl::trace(false, "fixme: %s(%d): "message"\n", __FUNCTION__, __LINE__, __VA_ARGS__)
+#endif
+
+// A macro to output a function call and its arguments to the debugging log, in case of error.
+#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF)
+#define ERR(message, ...) (void(0))
+#else
+#define ERR(message, ...) gl::trace(false, "err: %s(%d): "message"\n", __FUNCTION__, __LINE__, __VA_ARGS__)
+#endif
+
+// A macro to log a performance event around a scope.
+#if defined(ANGLE_DISABLE_TRACE) && defined(ANGLE_DISABLE_PERF)
+#define EVENT(message, ...) (void(0))
+#else
+#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__(__FUNCTION__ message "\n", __VA_ARGS__);
+#endif
+
+// A macro asserting a condition and outputting failures to the debug log
+#if !defined(NDEBUG)
+#define ASSERT(expression) do { \
+ if(!(expression)) \
+ ERR("\t! Assert failed in %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
+ assert(expression); \
+ } while(0)
+#else
+#define ASSERT(expression) (void(0))
+#endif
+
+// A macro to indicate unimplemented functionality
+#if !defined(NDEBUG)
+#define UNIMPLEMENTED() do { \
+ FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+ } while(0)
+#else
+ #define UNIMPLEMENTED() FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__)
+#endif
+
+// A macro for code which is not expected to be reached under valid assumptions
+#if !defined(NDEBUG)
+#define UNREACHABLE() do { \
+ ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+ } while(0)
+#else
+ #define UNREACHABLE() ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__)
+#endif
+
+// A macro functioning as a compile-time assert to validate constant conditions
+#define META_ASSERT(condition) typedef int COMPILE_TIME_ASSERT_##__LINE__[static_cast<bool>(condition)?1:-1]
+
+#endif // COMMON_DEBUG_H_
diff --git a/Source/ThirdParty/ANGLE/src/common/version.h b/Source/ThirdParty/ANGLE/src/common/version.h
new file mode 100644
index 000000000..4763332e7
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/common/version.h
@@ -0,0 +1,10 @@
+#define MAJOR_VERSION 0
+#define MINOR_VERSION 0
+#define BUILD_VERSION 0
+#define BUILD_REVISION 696
+
+#define STRINGIFY(x) #x
+#define MACRO_STRINGIFY(x) STRINGIFY(x)
+
+#define REVISION_STRING MACRO_STRINGIFY(BUILD_REVISION)
+#define VERSION_STRING MACRO_STRINGIFY(MAJOR_VERSION) "." MACRO_STRINGIFY(MINOR_VERSION) "." MACRO_STRINGIFY(BUILD_VERSION) "." MACRO_STRINGIFY(BUILD_REVISION)
diff --git a/Source/ThirdParty/ANGLE/src/compiler/BaseTypes.h b/Source/ThirdParty/ANGLE/src/compiler/BaseTypes.h
new file mode 100644
index 000000000..9f4a86020
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/BaseTypes.h
@@ -0,0 +1,147 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _BASICTYPES_INCLUDED_
+#define _BASICTYPES_INCLUDED_
+
+//
+// Precision qualifiers
+//
+enum TPrecision
+{
+ // These need to be kept sorted
+ EbpUndefined,
+ EbpLow,
+ EbpMedium,
+ EbpHigh,
+};
+
+inline const char* getPrecisionString(TPrecision p)
+{
+ switch(p)
+ {
+ case EbpHigh: return "highp"; break;
+ case EbpMedium: return "mediump"; break;
+ case EbpLow: return "lowp"; break;
+ default: return "mediump"; break; // Safest fallback
+ }
+}
+
+//
+// Basic type. Arrays, vectors, etc., are orthogonal to this.
+//
+enum TBasicType
+{
+ EbtVoid,
+ EbtFloat,
+ EbtInt,
+ EbtBool,
+ EbtGuardSamplerBegin, // non type: see implementation of IsSampler()
+ EbtSampler2D,
+ EbtSamplerCube,
+ EbtGuardSamplerEnd, // non type: see implementation of IsSampler()
+ EbtStruct,
+ EbtAddress, // should be deprecated??
+};
+
+inline const char* getBasicString(TBasicType t)
+{
+ switch (t)
+ {
+ case EbtVoid: return "void"; break;
+ case EbtFloat: return "float"; break;
+ case EbtInt: return "int"; break;
+ case EbtBool: return "bool"; break;
+ case EbtSampler2D: return "sampler2D"; break;
+ case EbtSamplerCube: return "samplerCube"; break;
+ case EbtStruct: return "structure"; break;
+ default: return "unknown type";
+ }
+}
+
+inline bool IsSampler(TBasicType type)
+{
+ return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd;
+}
+
+//
+// Qualifiers and built-ins. These are mainly used to see what can be read
+// or written, and by the machine dependent translator to know which registers
+// to allocate variables in. Since built-ins tend to go to different registers
+// than varying or uniform, it makes sense they are peers, not sub-classes.
+//
+enum TQualifier
+{
+ EvqTemporary, // For temporaries (within a function), read/write
+ EvqGlobal, // For globals read/write
+ EvqConst, // User defined constants and non-output parameters in functions
+ EvqAttribute, // Readonly
+ EvqVaryingIn, // readonly, fragment shaders only
+ EvqVaryingOut, // vertex shaders only read/write
+ EvqInvariantVaryingIn, // readonly, fragment shaders only
+ EvqInvariantVaryingOut, // vertex shaders only read/write
+ EvqUniform, // Readonly, vertex and fragment
+
+ // pack/unpack input and output
+ EvqInput,
+ EvqOutput,
+
+ // parameters
+ EvqIn,
+ EvqOut,
+ EvqInOut,
+ EvqConstReadOnly,
+
+ // built-ins written by vertex shader
+ EvqPosition,
+ EvqPointSize,
+
+ // built-ins read by fragment shader
+ EvqFragCoord,
+ EvqFrontFacing,
+ EvqPointCoord,
+
+ // built-ins written by fragment shader
+ EvqFragColor,
+ EvqFragData,
+
+ // end of list
+ EvqLast,
+};
+
+//
+// This is just for debug print out, carried along with the definitions above.
+//
+inline const char* getQualifierString(TQualifier q)
+{
+ switch(q)
+ {
+ case EvqTemporary: return "Temporary"; break;
+ case EvqGlobal: return "Global"; break;
+ case EvqConst: return "const"; break;
+ case EvqConstReadOnly: return "const"; break;
+ case EvqAttribute: return "attribute"; break;
+ case EvqVaryingIn: return "varying"; break;
+ case EvqVaryingOut: return "varying"; break;
+ case EvqInvariantVaryingIn: return "invariant varying"; break;
+ case EvqInvariantVaryingOut:return "invariant varying"; break;
+ case EvqUniform: return "uniform"; break;
+ case EvqIn: return "in"; break;
+ case EvqOut: return "out"; break;
+ case EvqInOut: return "inout"; break;
+ case EvqInput: return "input"; break;
+ case EvqOutput: return "output"; break;
+ case EvqPosition: return "Position"; break;
+ case EvqPointSize: return "PointSize"; break;
+ case EvqFragCoord: return "FragCoord"; break;
+ case EvqFrontFacing: return "FrontFacing"; break;
+ case EvqFragColor: return "FragColor"; break;
+ case EvqFragData: return "FragData"; break;
+ default: return "unknown qualifier";
+ }
+}
+
+#endif // _BASICTYPES_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/CodeGenGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/CodeGenGLSL.cpp
new file mode 100644
index 000000000..226bf8f0f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/CodeGenGLSL.cpp
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorGLSL.h"
+#include "compiler/TranslatorESSL.h"
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code. It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+{
+ switch (output) {
+ case SH_GLSL_OUTPUT:
+ return new TranslatorGLSL(type, spec);
+ case SH_ESSL_OUTPUT:
+ return new TranslatorESSL(type, spec);
+ default:
+ return NULL;
+ }
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+ delete compiler;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/CodeGenHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/CodeGenHLSL.cpp
new file mode 100644
index 000000000..f46ff66d4
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/CodeGenHLSL.cpp
@@ -0,0 +1,31 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorHLSL.h"
+
+//
+// This function must be provided to create the actual
+// compile object used by higher level code. It returns
+// a subclass of TCompiler.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
+{
+ switch (output) {
+ case SH_HLSL_OUTPUT:
+ return new TranslatorHLSL(type, spec);
+ default:
+ return NULL;
+ }
+}
+
+//
+// Delete the compiler made by ConstructCompiler
+//
+void DeleteCompiler(TCompiler* compiler)
+{
+ delete compiler;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Common.h b/Source/ThirdParty/ANGLE/src/compiler/Common.h
new file mode 100644
index 000000000..27a559829
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/Common.h
@@ -0,0 +1,89 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _COMMON_INCLUDED_
+#define _COMMON_INCLUDED_
+
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "compiler/PoolAlloc.h"
+
+// We need two pieces of information to report errors/warnings - string and
+// line number. We encode these into a single int so that it can be easily
+// incremented/decremented by lexer. The right SOURCE_LOC_LINE_SIZE bits store
+// line number while the rest store the string number. Since the shaders are
+// usually small, we should not run out of memory. SOURCE_LOC_LINE_SIZE
+// can be increased to alleviate this issue.
+typedef int TSourceLoc;
+const unsigned int SOURCE_LOC_LINE_SIZE = 16; // in bits.
+const unsigned int SOURCE_LOC_LINE_MASK = (1 << SOURCE_LOC_LINE_SIZE) - 1;
+
+inline TSourceLoc EncodeSourceLoc(int string, int line) {
+ return (string << SOURCE_LOC_LINE_SIZE) | (line & SOURCE_LOC_LINE_MASK);
+}
+
+inline void DecodeSourceLoc(TSourceLoc loc, int* string, int* line) {
+ if (string) *string = loc >> SOURCE_LOC_LINE_SIZE;
+ if (line) *line = loc & SOURCE_LOC_LINE_MASK;
+}
+
+//
+// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme.
+//
+#define POOL_ALLOCATOR_NEW_DELETE(A) \
+ void* operator new(size_t s) { return (A).allocate(s); } \
+ void* operator new(size_t, void *_Where) { return (_Where); } \
+ void operator delete(void*) { } \
+ void operator delete(void *, void *) { } \
+ void* operator new[](size_t s) { return (A).allocate(s); } \
+ void* operator new[](size_t, void *_Where) { return (_Where); } \
+ void operator delete[](void*) { } \
+ void operator delete[](void *, void *) { }
+
+//
+// Pool version of string.
+//
+typedef pool_allocator<char> TStringAllocator;
+typedef std::basic_string <char, std::char_traits<char>, TStringAllocator> TString;
+typedef std::basic_ostringstream<char, std::char_traits<char>, TStringAllocator> TStringStream;
+inline TString* NewPoolTString(const char* s)
+{
+ void* memory = GlobalPoolAllocator.allocate(sizeof(TString));
+ return new(memory) TString(s);
+}
+
+//
+// Persistent string memory. Should only be used for strings that survive
+// across compiles.
+//
+#define TPersistString std::string
+#define TPersistStringStream std::ostringstream
+
+//
+// Pool allocator versions of vectors, lists, and maps
+//
+template <class T> class TVector : public std::vector<T, pool_allocator<T> > {
+public:
+ typedef typename std::vector<T, pool_allocator<T> >::size_type size_type;
+ TVector() : std::vector<T, pool_allocator<T> >() {}
+ TVector(const pool_allocator<T>& a) : std::vector<T, pool_allocator<T> >(a) {}
+ TVector(size_type i): std::vector<T, pool_allocator<T> >(i) {}
+};
+
+template <class K, class D, class CMP = std::less<K> >
+class TMap : public std::map<K, D, CMP, pool_allocator<std::pair<const K, D> > > {
+public:
+ typedef pool_allocator<std::pair<const K, D> > tAllocator;
+
+ TMap() : std::map<K, D, CMP, tAllocator>() {}
+ // use correct two-stage name lookup supported in gcc 3.4 and above
+ TMap(const tAllocator& a) : std::map<K, D, CMP, tAllocator>(std::map<K, D, CMP, tAllocator>::key_compare(), a) {}
+};
+
+#endif // _COMMON_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Compiler.cpp b/Source/ThirdParty/ANGLE/src/compiler/Compiler.cpp
new file mode 100644
index 000000000..5d86a3ec0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/Compiler.cpp
@@ -0,0 +1,224 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/Initialize.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/ShHandle.h"
+#include "compiler/ValidateLimitations.h"
+#include "compiler/MapLongVariableNames.h"
+
+namespace {
+bool InitializeSymbolTable(
+ const TBuiltInStrings& builtInStrings,
+ ShShaderType type, ShShaderSpec spec, const ShBuiltInResources& resources,
+ TInfoSink& infoSink, TSymbolTable& symbolTable)
+{
+ TIntermediate intermediate(infoSink);
+ TExtensionBehavior extBehavior;
+ // The builtins deliberately don't specify precisions for the function
+ // arguments and return types. For that reason we don't try to check them.
+ TParseContext parseContext(symbolTable, extBehavior, intermediate, type, spec, 0, false, NULL, infoSink);
+
+ GlobalParseContext = &parseContext;
+
+ assert(symbolTable.isEmpty());
+ //
+ // Parse the built-ins. This should only happen once per
+ // language symbol table.
+ //
+ // Push the symbol table to give it an initial scope. This
+ // push should not have a corresponding pop, so that built-ins
+ // are preserved, and the test for an empty table fails.
+ //
+ symbolTable.push();
+
+ for (TBuiltInStrings::const_iterator i = builtInStrings.begin(); i != builtInStrings.end(); ++i)
+ {
+ const char* builtInShaders = i->c_str();
+ int builtInLengths = static_cast<int>(i->size());
+ if (builtInLengths <= 0)
+ continue;
+
+ if (PaParseStrings(1, &builtInShaders, &builtInLengths, &parseContext) != 0)
+ {
+ infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins");
+ return false;
+ }
+ }
+
+ IdentifyBuiltIns(type, spec, resources, symbolTable);
+
+ return true;
+}
+
+class TScopedPoolAllocator {
+public:
+ TScopedPoolAllocator(TPoolAllocator* allocator, bool pushPop)
+ : mAllocator(allocator), mPushPopAllocator(pushPop) {
+ if (mPushPopAllocator) mAllocator->push();
+ SetGlobalPoolAllocator(mAllocator);
+ }
+ ~TScopedPoolAllocator() {
+ SetGlobalPoolAllocator(NULL);
+ if (mPushPopAllocator) mAllocator->pop();
+ }
+
+private:
+ TPoolAllocator* mAllocator;
+ bool mPushPopAllocator;
+};
+} // namespace
+
+TShHandleBase::TShHandleBase() {
+ allocator.push();
+ SetGlobalPoolAllocator(&allocator);
+}
+
+TShHandleBase::~TShHandleBase() {
+ SetGlobalPoolAllocator(NULL);
+ allocator.popAll();
+}
+
+TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
+ : shaderType(type),
+ shaderSpec(spec)
+{
+}
+
+TCompiler::~TCompiler()
+{
+}
+
+bool TCompiler::Init(const ShBuiltInResources& resources)
+{
+ TScopedPoolAllocator scopedAlloc(&allocator, false);
+
+ // Generate built-in symbol table.
+ if (!InitBuiltInSymbolTable(resources))
+ return false;
+ InitExtensionBehavior(resources, extensionBehavior);
+
+ return true;
+}
+
+bool TCompiler::compile(const char* const shaderStrings[],
+ const int numStrings,
+ int compileOptions)
+{
+ TScopedPoolAllocator scopedAlloc(&allocator, true);
+ clearResults();
+
+ if (numStrings == 0)
+ return true;
+
+ // If compiling for WebGL, validate loop and indexing as well.
+ if (shaderSpec == SH_WEBGL_SPEC)
+ compileOptions |= SH_VALIDATE_LOOP_INDEXING;
+
+ // First string is path of source file if flag is set. The actual source follows.
+ const char* sourcePath = NULL;
+ int firstSource = 0;
+ if (compileOptions & SH_SOURCE_PATH)
+ {
+ sourcePath = shaderStrings[0];
+ ++firstSource;
+ }
+
+ TIntermediate intermediate(infoSink);
+ TParseContext parseContext(symbolTable, extensionBehavior, intermediate,
+ shaderType, shaderSpec, compileOptions, true,
+ sourcePath, infoSink);
+ GlobalParseContext = &parseContext;
+
+ // We preserve symbols at the built-in level from compile-to-compile.
+ // Start pushing the user-defined symbols at global level.
+ symbolTable.push();
+ if (!symbolTable.atGlobalLevel())
+ infoSink.info.message(EPrefixInternalError, "Wrong symbol table level");
+
+ // Parse shader.
+ bool success =
+ (PaParseStrings(numStrings - firstSource, &shaderStrings[firstSource], NULL, &parseContext) == 0) &&
+ (parseContext.treeRoot != NULL);
+ if (success) {
+ TIntermNode* root = parseContext.treeRoot;
+ success = intermediate.postProcess(root);
+
+ if (success && (compileOptions & SH_VALIDATE_LOOP_INDEXING))
+ success = validateLimitations(root);
+
+ // Call mapLongVariableNames() before collectAttribsUniforms() so in
+ // collectAttribsUniforms() we already have the mapped symbol names and
+ // we could composite mapped and original variable names.
+ if (compileOptions & SH_MAP_LONG_VARIABLE_NAMES)
+ mapLongVariableNames(root);
+
+ if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS))
+ collectAttribsUniforms(root);
+
+ if (success && (compileOptions & SH_INTERMEDIATE_TREE))
+ intermediate.outputTree(root);
+
+ if (success && (compileOptions & SH_OBJECT_CODE))
+ translate(root);
+ }
+
+ // Cleanup memory.
+ intermediate.remove(parseContext.treeRoot);
+ // Ensure symbol table is returned to the built-in level,
+ // throwing away all but the built-ins.
+ while (!symbolTable.atBuiltInLevel())
+ symbolTable.pop();
+
+ return success;
+}
+
+bool TCompiler::InitBuiltInSymbolTable(const ShBuiltInResources& resources)
+{
+ TBuiltIns builtIns;
+
+ builtIns.initialize(shaderType, shaderSpec, resources);
+ return InitializeSymbolTable(builtIns.getBuiltInStrings(),
+ shaderType, shaderSpec, resources, infoSink, symbolTable);
+}
+
+void TCompiler::clearResults()
+{
+ infoSink.info.erase();
+ infoSink.obj.erase();
+ infoSink.debug.erase();
+
+ attribs.clear();
+ uniforms.clear();
+}
+
+bool TCompiler::validateLimitations(TIntermNode* root) {
+ ValidateLimitations validate(shaderType, infoSink.info);
+ root->traverse(&validate);
+ return validate.numErrors() == 0;
+}
+
+void TCompiler::collectAttribsUniforms(TIntermNode* root)
+{
+ CollectAttribsUniforms collect(attribs, uniforms);
+ root->traverse(&collect);
+}
+
+void TCompiler::mapLongVariableNames(TIntermNode* root)
+{
+ MapLongVariableNames map(varyingLongNameMap);
+ root->traverse(&map);
+}
+
+int TCompiler::getMappedNameMaxLength() const
+{
+ return MAX_IDENTIFIER_NAME_SIZE + 1;
+}
+
+const TExtensionBehavior& TCompiler::getExtensionBehavior() const
+{
+ return extensionBehavior;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ConstantUnion.h b/Source/ThirdParty/ANGLE/src/compiler/ConstantUnion.h
new file mode 100644
index 000000000..d28a11b8b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ConstantUnion.h
@@ -0,0 +1,258 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _CONSTANT_UNION_INCLUDED_
+#define _CONSTANT_UNION_INCLUDED_
+
+#include <assert.h>
+
+class ConstantUnion {
+public:
+
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+ void setIConst(int i) {iConst = i; type = EbtInt; }
+ void setFConst(float f) {fConst = f; type = EbtFloat; }
+ void setBConst(bool b) {bConst = b; type = EbtBool; }
+
+ int getIConst() { return iConst; }
+ float getFConst() { return fConst; }
+ bool getBConst() { return bConst; }
+ int getIConst() const { return iConst; }
+ float getFConst() const { return fConst; }
+ bool getBConst() const { return bConst; }
+
+ bool operator==(const int i) const
+ {
+ return i == iConst;
+ }
+
+ bool operator==(const float f) const
+ {
+ return f == fConst;
+ }
+
+ bool operator==(const bool b) const
+ {
+ return b == bConst;
+ }
+
+ bool operator==(const ConstantUnion& constant) const
+ {
+ if (constant.type != type)
+ return false;
+
+ switch (type) {
+ case EbtInt:
+ return constant.iConst == iConst;
+ case EbtFloat:
+ return constant.fConst == fConst;
+ case EbtBool:
+ return constant.bConst == bConst;
+ default:
+ return false;
+ }
+
+ return false;
+ }
+
+ bool operator!=(const int i) const
+ {
+ return !operator==(i);
+ }
+
+ bool operator!=(const float f) const
+ {
+ return !operator==(f);
+ }
+
+ bool operator!=(const bool b) const
+ {
+ return !operator==(b);
+ }
+
+ bool operator!=(const ConstantUnion& constant) const
+ {
+ return !operator==(constant);
+ }
+
+ bool operator>(const ConstantUnion& constant) const
+ {
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt:
+ return iConst > constant.iConst;
+ case EbtFloat:
+ return fConst > constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+
+ return false;
+ }
+
+ bool operator<(const ConstantUnion& constant) const
+ {
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt:
+ return iConst < constant.iConst;
+ case EbtFloat:
+ return fConst < constant.fConst;
+ default:
+ return false; // Invalid operation, handled at semantic analysis
+ }
+
+ return false;
+ }
+
+ ConstantUnion operator+(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst + constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator-(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst - constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator*(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst * constant.iConst); break;
+ case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator%(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst % constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator>>(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator<<(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst << constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator&(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst & constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator|(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst | constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator^(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator&&(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtBool: returnValue.setBConst(bConst && constant.bConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ ConstantUnion operator||(const ConstantUnion& constant) const
+ {
+ ConstantUnion returnValue;
+ assert(type == constant.type);
+ switch (type) {
+ case EbtBool: returnValue.setBConst(bConst || constant.bConst); break;
+ default: assert(false && "Default missing");
+ }
+
+ return returnValue;
+ }
+
+ TBasicType getType() const { return type; }
+private:
+
+ union {
+ int iConst; // used for ivec, scalar ints
+ bool bConst; // used for bvec, scalar bools
+ float fConst; // used for vec, mat, scalar floats
+ } ;
+
+ TBasicType type;
+};
+
+#endif // _CONSTANT_UNION_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ExtensionBehavior.h b/Source/ThirdParty/ANGLE/src/compiler/ExtensionBehavior.h
new file mode 100644
index 000000000..ab5a0a53b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ExtensionBehavior.h
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _EXTENSION_BEHAVIOR_INCLUDED_
+#define _EXTENSION_BEHAVIOR_INCLUDED_
+
+#include "compiler/Common.h"
+
+typedef enum {
+ EBhRequire,
+ EBhEnable,
+ EBhWarn,
+ EBhDisable
+} TBehavior;
+
+inline const char* getBehaviorString(TBehavior b)
+{
+ switch(b) {
+ case EBhRequire:
+ return "require";
+ case EBhEnable:
+ return "enable";
+ case EBhWarn:
+ return "warn";
+ case EBhDisable:
+ return "disable";
+ default:
+ return NULL;
+ }
+}
+
+typedef TMap<TString, TBehavior> TExtensionBehavior;
+
+#endif // _EXTENSION_TABLE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.cpp b/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.cpp
new file mode 100644
index 000000000..d631af44f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.cpp
@@ -0,0 +1,172 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/ForLoopUnroll.h"
+
+void ForLoopUnroll::FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info)
+{
+ ASSERT(node->getType() == ELoopFor);
+ ASSERT(node->getUnrollFlag());
+
+ TIntermNode* init = node->getInit();
+ ASSERT(init != NULL);
+ TIntermAggregate* decl = init->getAsAggregate();
+ ASSERT((decl != NULL) && (decl->getOp() == EOpDeclaration));
+ TIntermSequence& declSeq = decl->getSequence();
+ ASSERT(declSeq.size() == 1);
+ TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
+ ASSERT((declInit != NULL) && (declInit->getOp() == EOpInitialize));
+ TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
+ ASSERT(symbol != NULL);
+ ASSERT(symbol->getBasicType() == EbtInt);
+
+ info.id = symbol->getId();
+
+ ASSERT(declInit->getRight() != NULL);
+ TIntermConstantUnion* initNode = declInit->getRight()->getAsConstantUnion();
+ ASSERT(initNode != NULL);
+
+ info.initValue = evaluateIntConstant(initNode);
+ info.currentValue = info.initValue;
+
+ TIntermNode* cond = node->getCondition();
+ ASSERT(cond != NULL);
+ TIntermBinary* binOp = cond->getAsBinaryNode();
+ ASSERT(binOp != NULL);
+ ASSERT(binOp->getRight() != NULL);
+ ASSERT(binOp->getRight()->getAsConstantUnion() != NULL);
+
+ info.incrementValue = getLoopIncrement(node);
+ info.stopValue = evaluateIntConstant(
+ binOp->getRight()->getAsConstantUnion());
+ info.op = binOp->getOp();
+}
+
+void ForLoopUnroll::Step()
+{
+ ASSERT(mLoopIndexStack.size() > 0);
+ TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
+ info.currentValue += info.incrementValue;
+}
+
+bool ForLoopUnroll::SatisfiesLoopCondition()
+{
+ ASSERT(mLoopIndexStack.size() > 0);
+ TLoopIndexInfo& info = mLoopIndexStack[mLoopIndexStack.size() - 1];
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (info.op) {
+ case EOpEqual:
+ return (info.currentValue == info.stopValue);
+ case EOpNotEqual:
+ return (info.currentValue != info.stopValue);
+ case EOpLessThan:
+ return (info.currentValue < info.stopValue);
+ case EOpGreaterThan:
+ return (info.currentValue > info.stopValue);
+ case EOpLessThanEqual:
+ return (info.currentValue <= info.stopValue);
+ case EOpGreaterThanEqual:
+ return (info.currentValue >= info.stopValue);
+ default:
+ UNREACHABLE();
+ }
+ return false;
+}
+
+bool ForLoopUnroll::NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol)
+{
+ for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
+ i != mLoopIndexStack.end();
+ ++i) {
+ if (i->id == symbol->getId())
+ return true;
+ }
+ return false;
+}
+
+int ForLoopUnroll::GetLoopIndexValue(TIntermSymbol* symbol)
+{
+ for (TVector<TLoopIndexInfo>::iterator i = mLoopIndexStack.begin();
+ i != mLoopIndexStack.end();
+ ++i) {
+ if (i->id == symbol->getId())
+ return i->currentValue;
+ }
+ UNREACHABLE();
+ return false;
+}
+
+void ForLoopUnroll::Push(TLoopIndexInfo& info)
+{
+ mLoopIndexStack.push_back(info);
+}
+
+void ForLoopUnroll::Pop()
+{
+ mLoopIndexStack.pop_back();
+}
+
+int ForLoopUnroll::getLoopIncrement(TIntermLoop* node)
+{
+ TIntermNode* expr = node->getExpression();
+ ASSERT(expr != NULL);
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary* unOp = expr->getAsUnaryNode();
+ TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermConstantUnion* incrementNode = NULL;
+ if (unOp != NULL) {
+ op = unOp->getOp();
+ } else if (binOp != NULL) {
+ op = binOp->getOp();
+ ASSERT(binOp->getRight() != NULL);
+ incrementNode = binOp->getRight()->getAsConstantUnion();
+ ASSERT(incrementNode != NULL);
+ }
+
+ int increment = 0;
+ // The operator is one of: ++ -- += -=.
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ increment = 1;
+ break;
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ increment = -1;
+ break;
+ case EOpAddAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ increment = evaluateIntConstant(incrementNode);
+ break;
+ case EOpSubAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ increment = - evaluateIntConstant(incrementNode);
+ break;
+ default:
+ ASSERT(false);
+ }
+
+ return increment;
+}
+
+int ForLoopUnroll::evaluateIntConstant(TIntermConstantUnion* node)
+{
+ ASSERT((node != NULL) && (node->getUnionArrayPointer() != NULL));
+ return node->getUnionArrayPointer()->getIConst();
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.h b/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.h
new file mode 100644
index 000000000..b2b2b58c1
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ForLoopUnroll.h
@@ -0,0 +1,46 @@
+//
+// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+
+struct TLoopIndexInfo {
+ int id;
+ int initValue;
+ int stopValue;
+ int incrementValue;
+ TOperator op;
+ int currentValue;
+};
+
+class ForLoopUnroll {
+public:
+ ForLoopUnroll() { }
+
+ void FillLoopIndexInfo(TIntermLoop* node, TLoopIndexInfo& info);
+
+ // Update the info.currentValue for the next loop iteration.
+ void Step();
+
+ // Return false if loop condition is no longer satisfied.
+ bool SatisfiesLoopCondition();
+
+ // Check if the symbol is the index of a loop that's unrolled.
+ bool NeedsToReplaceSymbolWithValue(TIntermSymbol* symbol);
+
+ // Return the current value of a given loop index symbol.
+ int GetLoopIndexValue(TIntermSymbol* symbol);
+
+ void Push(TLoopIndexInfo& info);
+ void Pop();
+
+private:
+ int getLoopIncrement(TIntermLoop* node);
+
+ int evaluateIntConstant(TIntermConstantUnion* node);
+
+ TVector<TLoopIndexInfo> mLoopIndexStack;
+};
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InfoSink.cpp b/Source/ThirdParty/ANGLE/src/compiler/InfoSink.cpp
new file mode 100644
index 000000000..ba32f781f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/InfoSink.cpp
@@ -0,0 +1,59 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/InfoSink.h"
+
+void TInfoSinkBase::prefix(TPrefixType message) {
+ switch(message) {
+ case EPrefixNone:
+ break;
+ case EPrefixWarning:
+ sink.append("WARNING: ");
+ break;
+ case EPrefixError:
+ sink.append("ERROR: ");
+ break;
+ case EPrefixInternalError:
+ sink.append("INTERNAL ERROR: ");
+ break;
+ case EPrefixUnimplemented:
+ sink.append("UNIMPLEMENTED: ");
+ break;
+ case EPrefixNote:
+ sink.append("NOTE: ");
+ break;
+ default:
+ sink.append("UNKOWN ERROR: ");
+ break;
+ }
+}
+
+void TInfoSinkBase::location(TSourceLoc loc) {
+ int string = 0, line = 0;
+ DecodeSourceLoc(loc, &string, &line);
+
+ TPersistStringStream stream;
+ if (line)
+ stream << string << ":" << line;
+ else
+ stream << string << ":? ";
+ stream << ": ";
+
+ sink.append(stream.str());
+}
+
+void TInfoSinkBase::message(TPrefixType message, const char* s) {
+ prefix(message);
+ sink.append(s);
+ sink.append("\n");
+}
+
+void TInfoSinkBase::message(TPrefixType message, const char* s, TSourceLoc loc) {
+ prefix(message);
+ location(loc);
+ sink.append(s);
+ sink.append("\n");
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InfoSink.h b/Source/ThirdParty/ANGLE/src/compiler/InfoSink.h
new file mode 100644
index 000000000..e2224e918
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/InfoSink.h
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _INFOSINK_INCLUDED_
+#define _INFOSINK_INCLUDED_
+
+#include <math.h>
+#include "compiler/Common.h"
+
+// Returns the fractional part of the given floating-point number.
+inline float fractionalPart(float f) {
+ float intPart = 0.0f;
+ return modff(f, &intPart);
+}
+
+//
+// TPrefixType is used to centralize how info log messages start.
+// See below.
+//
+enum TPrefixType {
+ EPrefixNone,
+ EPrefixWarning,
+ EPrefixError,
+ EPrefixInternalError,
+ EPrefixUnimplemented,
+ EPrefixNote
+};
+
+//
+// Encapsulate info logs for all objects that have them.
+//
+// The methods are a general set of tools for getting a variety of
+// messages and types inserted into the log.
+//
+class TInfoSinkBase {
+public:
+ TInfoSinkBase() {}
+
+ template <typename T>
+ TInfoSinkBase& operator<<(const T& t) {
+ TPersistStringStream stream;
+ stream << t;
+ sink.append(stream.str());
+ return *this;
+ }
+ // Override << operator for specific types. It is faster to append strings
+ // and characters directly to the sink.
+ TInfoSinkBase& operator<<(char c) {
+ sink.append(1, c);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const char* str) {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const TPersistString& str) {
+ sink.append(str);
+ return *this;
+ }
+ TInfoSinkBase& operator<<(const TString& str) {
+ sink.append(str.c_str());
+ return *this;
+ }
+ // Make sure floats are written with correct precision.
+ TInfoSinkBase& operator<<(float f) {
+ // Make sure that at least one decimal point is written. If a number
+ // does not have a fractional part, the default precision format does
+ // not write the decimal portion which gets interpreted as integer by
+ // the compiler.
+ TPersistStringStream stream;
+ if (fractionalPart(f) == 0.0f) {
+ stream.precision(1);
+ stream << std::showpoint << std::fixed << f;
+ } else {
+ stream.unsetf(std::ios::fixed);
+ stream.unsetf(std::ios::scientific);
+ stream.precision(8);
+ stream << f;
+ }
+ sink.append(stream.str());
+ return *this;
+ }
+ // Write boolean values as their names instead of integral value.
+ TInfoSinkBase& operator<<(bool b) {
+ const char* str = b ? "true" : "false";
+ sink.append(str);
+ return *this;
+ }
+
+ void erase() { sink.clear(); }
+ int size() { return static_cast<int>(sink.size()); }
+
+ const TPersistString& str() const { return sink; }
+ const char* c_str() const { return sink.c_str(); }
+
+ void prefix(TPrefixType message);
+ void location(TSourceLoc loc);
+ void message(TPrefixType message, const char* s);
+ void message(TPrefixType message, const char* s, TSourceLoc loc);
+
+private:
+ TPersistString sink;
+};
+
+class TInfoSink {
+public:
+ TInfoSinkBase info;
+ TInfoSinkBase debug;
+ TInfoSinkBase obj;
+};
+
+#endif // _INFOSINK_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Initialize.cpp b/Source/ThirdParty/ANGLE/src/compiler/Initialize.cpp
new file mode 100644
index 000000000..74a2de36e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/Initialize.cpp
@@ -0,0 +1,629 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Create strings that declare built-in definitions, add built-ins that
+// cannot be expressed in the files, and establish mappings between
+// built-in functions and operators.
+//
+
+#include "compiler/Initialize.h"
+
+#include "compiler/intermediate.h"
+
+//============================================================================
+//
+// Prototypes for built-in functions seen by both vertex and fragment shaders.
+//
+//============================================================================
+static TString BuiltInFunctionsCommon()
+{
+ TString s;
+
+ //
+ // Angle and Trigonometric Functions.
+ //
+ s.append(TString("float radians(float degrees);"));
+ s.append(TString("vec2 radians(vec2 degrees);"));
+ s.append(TString("vec3 radians(vec3 degrees);"));
+ s.append(TString("vec4 radians(vec4 degrees);"));
+
+ s.append(TString("float degrees(float radians);"));
+ s.append(TString("vec2 degrees(vec2 radians);"));
+ s.append(TString("vec3 degrees(vec3 radians);"));
+ s.append(TString("vec4 degrees(vec4 radians);"));
+
+ s.append(TString("float sin(float angle);"));
+ s.append(TString("vec2 sin(vec2 angle);"));
+ s.append(TString("vec3 sin(vec3 angle);"));
+ s.append(TString("vec4 sin(vec4 angle);"));
+
+ s.append(TString("float cos(float angle);"));
+ s.append(TString("vec2 cos(vec2 angle);"));
+ s.append(TString("vec3 cos(vec3 angle);"));
+ s.append(TString("vec4 cos(vec4 angle);"));
+
+ s.append(TString("float tan(float angle);"));
+ s.append(TString("vec2 tan(vec2 angle);"));
+ s.append(TString("vec3 tan(vec3 angle);"));
+ s.append(TString("vec4 tan(vec4 angle);"));
+
+ s.append(TString("float asin(float x);"));
+ s.append(TString("vec2 asin(vec2 x);"));
+ s.append(TString("vec3 asin(vec3 x);"));
+ s.append(TString("vec4 asin(vec4 x);"));
+
+ s.append(TString("float acos(float x);"));
+ s.append(TString("vec2 acos(vec2 x);"));
+ s.append(TString("vec3 acos(vec3 x);"));
+ s.append(TString("vec4 acos(vec4 x);"));
+
+ s.append(TString("float atan(float y, float x);"));
+ s.append(TString("vec2 atan(vec2 y, vec2 x);"));
+ s.append(TString("vec3 atan(vec3 y, vec3 x);"));
+ s.append(TString("vec4 atan(vec4 y, vec4 x);"));
+
+ s.append(TString("float atan(float y_over_x);"));
+ s.append(TString("vec2 atan(vec2 y_over_x);"));
+ s.append(TString("vec3 atan(vec3 y_over_x);"));
+ s.append(TString("vec4 atan(vec4 y_over_x);"));
+
+ //
+ // Exponential Functions.
+ //
+ s.append(TString("float pow(float x, float y);"));
+ s.append(TString("vec2 pow(vec2 x, vec2 y);"));
+ s.append(TString("vec3 pow(vec3 x, vec3 y);"));
+ s.append(TString("vec4 pow(vec4 x, vec4 y);"));
+
+ s.append(TString("float exp(float x);"));
+ s.append(TString("vec2 exp(vec2 x);"));
+ s.append(TString("vec3 exp(vec3 x);"));
+ s.append(TString("vec4 exp(vec4 x);"));
+
+ s.append(TString("float log(float x);"));
+ s.append(TString("vec2 log(vec2 x);"));
+ s.append(TString("vec3 log(vec3 x);"));
+ s.append(TString("vec4 log(vec4 x);"));
+
+ s.append(TString("float exp2(float x);"));
+ s.append(TString("vec2 exp2(vec2 x);"));
+ s.append(TString("vec3 exp2(vec3 x);"));
+ s.append(TString("vec4 exp2(vec4 x);"));
+
+ s.append(TString("float log2(float x);"));
+ s.append(TString("vec2 log2(vec2 x);"));
+ s.append(TString("vec3 log2(vec3 x);"));
+ s.append(TString("vec4 log2(vec4 x);"));
+
+ s.append(TString("float sqrt(float x);"));
+ s.append(TString("vec2 sqrt(vec2 x);"));
+ s.append(TString("vec3 sqrt(vec3 x);"));
+ s.append(TString("vec4 sqrt(vec4 x);"));
+
+ s.append(TString("float inversesqrt(float x);"));
+ s.append(TString("vec2 inversesqrt(vec2 x);"));
+ s.append(TString("vec3 inversesqrt(vec3 x);"));
+ s.append(TString("vec4 inversesqrt(vec4 x);"));
+
+ //
+ // Common Functions.
+ //
+ s.append(TString("float abs(float x);"));
+ s.append(TString("vec2 abs(vec2 x);"));
+ s.append(TString("vec3 abs(vec3 x);"));
+ s.append(TString("vec4 abs(vec4 x);"));
+
+ s.append(TString("float sign(float x);"));
+ s.append(TString("vec2 sign(vec2 x);"));
+ s.append(TString("vec3 sign(vec3 x);"));
+ s.append(TString("vec4 sign(vec4 x);"));
+
+ s.append(TString("float floor(float x);"));
+ s.append(TString("vec2 floor(vec2 x);"));
+ s.append(TString("vec3 floor(vec3 x);"));
+ s.append(TString("vec4 floor(vec4 x);"));
+
+ s.append(TString("float ceil(float x);"));
+ s.append(TString("vec2 ceil(vec2 x);"));
+ s.append(TString("vec3 ceil(vec3 x);"));
+ s.append(TString("vec4 ceil(vec4 x);"));
+
+ s.append(TString("float fract(float x);"));
+ s.append(TString("vec2 fract(vec2 x);"));
+ s.append(TString("vec3 fract(vec3 x);"));
+ s.append(TString("vec4 fract(vec4 x);"));
+
+ s.append(TString("float mod(float x, float y);"));
+ s.append(TString("vec2 mod(vec2 x, float y);"));
+ s.append(TString("vec3 mod(vec3 x, float y);"));
+ s.append(TString("vec4 mod(vec4 x, float y);"));
+ s.append(TString("vec2 mod(vec2 x, vec2 y);"));
+ s.append(TString("vec3 mod(vec3 x, vec3 y);"));
+ s.append(TString("vec4 mod(vec4 x, vec4 y);"));
+
+ s.append(TString("float min(float x, float y);"));
+ s.append(TString("vec2 min(vec2 x, float y);"));
+ s.append(TString("vec3 min(vec3 x, float y);"));
+ s.append(TString("vec4 min(vec4 x, float y);"));
+ s.append(TString("vec2 min(vec2 x, vec2 y);"));
+ s.append(TString("vec3 min(vec3 x, vec3 y);"));
+ s.append(TString("vec4 min(vec4 x, vec4 y);"));
+
+ s.append(TString("float max(float x, float y);"));
+ s.append(TString("vec2 max(vec2 x, float y);"));
+ s.append(TString("vec3 max(vec3 x, float y);"));
+ s.append(TString("vec4 max(vec4 x, float y);"));
+ s.append(TString("vec2 max(vec2 x, vec2 y);"));
+ s.append(TString("vec3 max(vec3 x, vec3 y);"));
+ s.append(TString("vec4 max(vec4 x, vec4 y);"));
+
+ s.append(TString("float clamp(float x, float minVal, float maxVal);"));
+ s.append(TString("vec2 clamp(vec2 x, float minVal, float maxVal);"));
+ s.append(TString("vec3 clamp(vec3 x, float minVal, float maxVal);"));
+ s.append(TString("vec4 clamp(vec4 x, float minVal, float maxVal);"));
+ s.append(TString("vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal);"));
+ s.append(TString("vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal);"));
+ s.append(TString("vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal);"));
+
+ s.append(TString("float mix(float x, float y, float a);"));
+ s.append(TString("vec2 mix(vec2 x, vec2 y, float a);"));
+ s.append(TString("vec3 mix(vec3 x, vec3 y, float a);"));
+ s.append(TString("vec4 mix(vec4 x, vec4 y, float a);"));
+ s.append(TString("vec2 mix(vec2 x, vec2 y, vec2 a);"));
+ s.append(TString("vec3 mix(vec3 x, vec3 y, vec3 a);"));
+ s.append(TString("vec4 mix(vec4 x, vec4 y, vec4 a);"));
+
+ s.append(TString("float step(float edge, float x);"));
+ s.append(TString("vec2 step(vec2 edge, vec2 x);"));
+ s.append(TString("vec3 step(vec3 edge, vec3 x);"));
+ s.append(TString("vec4 step(vec4 edge, vec4 x);"));
+ s.append(TString("vec2 step(float edge, vec2 x);"));
+ s.append(TString("vec3 step(float edge, vec3 x);"));
+ s.append(TString("vec4 step(float edge, vec4 x);"));
+
+ s.append(TString("float smoothstep(float edge0, float edge1, float x);"));
+ s.append(TString("vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x);"));
+ s.append(TString("vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x);"));
+ s.append(TString("vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x);"));
+ s.append(TString("vec2 smoothstep(float edge0, float edge1, vec2 x);"));
+ s.append(TString("vec3 smoothstep(float edge0, float edge1, vec3 x);"));
+ s.append(TString("vec4 smoothstep(float edge0, float edge1, vec4 x);"));
+
+ //
+ // Geometric Functions.
+ //
+ s.append(TString("float length(float x);"));
+ s.append(TString("float length(vec2 x);"));
+ s.append(TString("float length(vec3 x);"));
+ s.append(TString("float length(vec4 x);"));
+
+ s.append(TString("float distance(float p0, float p1);"));
+ s.append(TString("float distance(vec2 p0, vec2 p1);"));
+ s.append(TString("float distance(vec3 p0, vec3 p1);"));
+ s.append(TString("float distance(vec4 p0, vec4 p1);"));
+
+ s.append(TString("float dot(float x, float y);"));
+ s.append(TString("float dot(vec2 x, vec2 y);"));
+ s.append(TString("float dot(vec3 x, vec3 y);"));
+ s.append(TString("float dot(vec4 x, vec4 y);"));
+
+ s.append(TString("vec3 cross(vec3 x, vec3 y);"));
+ s.append(TString("float normalize(float x);"));
+ s.append(TString("vec2 normalize(vec2 x);"));
+ s.append(TString("vec3 normalize(vec3 x);"));
+ s.append(TString("vec4 normalize(vec4 x);"));
+
+ s.append(TString("float faceforward(float N, float I, float Nref);"));
+ s.append(TString("vec2 faceforward(vec2 N, vec2 I, vec2 Nref);"));
+ s.append(TString("vec3 faceforward(vec3 N, vec3 I, vec3 Nref);"));
+ s.append(TString("vec4 faceforward(vec4 N, vec4 I, vec4 Nref);"));
+
+ s.append(TString("float reflect(float I, float N);"));
+ s.append(TString("vec2 reflect(vec2 I, vec2 N);"));
+ s.append(TString("vec3 reflect(vec3 I, vec3 N);"));
+ s.append(TString("vec4 reflect(vec4 I, vec4 N);"));
+
+ s.append(TString("float refract(float I, float N, float eta);"));
+ s.append(TString("vec2 refract(vec2 I, vec2 N, float eta);"));
+ s.append(TString("vec3 refract(vec3 I, vec3 N, float eta);"));
+ s.append(TString("vec4 refract(vec4 I, vec4 N, float eta);"));
+
+ //
+ // Matrix Functions.
+ //
+ s.append(TString("mat2 matrixCompMult(mat2 x, mat2 y);"));
+ s.append(TString("mat3 matrixCompMult(mat3 x, mat3 y);"));
+ s.append(TString("mat4 matrixCompMult(mat4 x, mat4 y);"));
+
+ //
+ // Vector relational functions.
+ //
+ s.append(TString("bvec2 lessThan(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 lessThan(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 lessThan(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 lessThan(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 lessThan(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 lessThan(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 lessThanEqual(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 lessThanEqual(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 lessThanEqual(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 lessThanEqual(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 lessThanEqual(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 lessThanEqual(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 greaterThan(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 greaterThan(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 greaterThan(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 greaterThan(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 greaterThan(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 greaterThan(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 greaterThanEqual(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 greaterThanEqual(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 greaterThanEqual(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 greaterThanEqual(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 greaterThanEqual(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 greaterThanEqual(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 equal(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 equal(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 equal(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 equal(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 equal(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 equal(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 equal(bvec2 x, bvec2 y);"));
+ s.append(TString("bvec3 equal(bvec3 x, bvec3 y);"));
+ s.append(TString("bvec4 equal(bvec4 x, bvec4 y);"));
+
+ s.append(TString("bvec2 notEqual(vec2 x, vec2 y);"));
+ s.append(TString("bvec3 notEqual(vec3 x, vec3 y);"));
+ s.append(TString("bvec4 notEqual(vec4 x, vec4 y);"));
+
+ s.append(TString("bvec2 notEqual(ivec2 x, ivec2 y);"));
+ s.append(TString("bvec3 notEqual(ivec3 x, ivec3 y);"));
+ s.append(TString("bvec4 notEqual(ivec4 x, ivec4 y);"));
+
+ s.append(TString("bvec2 notEqual(bvec2 x, bvec2 y);"));
+ s.append(TString("bvec3 notEqual(bvec3 x, bvec3 y);"));
+ s.append(TString("bvec4 notEqual(bvec4 x, bvec4 y);"));
+
+ s.append(TString("bool any(bvec2 x);"));
+ s.append(TString("bool any(bvec3 x);"));
+ s.append(TString("bool any(bvec4 x);"));
+
+ s.append(TString("bool all(bvec2 x);"));
+ s.append(TString("bool all(bvec3 x);"));
+ s.append(TString("bool all(bvec4 x);"));
+
+ s.append(TString("bvec2 not(bvec2 x);"));
+ s.append(TString("bvec3 not(bvec3 x);"));
+ s.append(TString("bvec4 not(bvec4 x);"));
+
+ //
+ // Noise functions.
+ //
+ //s.append(TString("float noise1(float x);"));
+ //s.append(TString("float noise1(vec2 x);"));
+ //s.append(TString("float noise1(vec3 x);"));
+ //s.append(TString("float noise1(vec4 x);"));
+
+ //s.append(TString("vec2 noise2(float x);"));
+ //s.append(TString("vec2 noise2(vec2 x);"));
+ //s.append(TString("vec2 noise2(vec3 x);"));
+ //s.append(TString("vec2 noise2(vec4 x);"));
+
+ //s.append(TString("vec3 noise3(float x);"));
+ //s.append(TString("vec3 noise3(vec2 x);"));
+ //s.append(TString("vec3 noise3(vec3 x);"));
+ //s.append(TString("vec3 noise3(vec4 x);"));
+
+ //s.append(TString("vec4 noise4(float x);"));
+ //s.append(TString("vec4 noise4(vec2 x);"));
+ //s.append(TString("vec4 noise4(vec3 x);"));
+ //s.append(TString("vec4 noise4(vec4 x);"));
+
+ return s;
+}
+
+//============================================================================
+//
+// Prototypes for built-in functions seen by vertex shaders only.
+//
+//============================================================================
+static TString BuiltInFunctionsVertex(const ShBuiltInResources& resources)
+{
+ TString s;
+
+ //
+ // Geometric Functions.
+ //
+ //s.append(TString("vec4 ftransform();"));
+
+ //
+ // Texture Functions.
+ //
+ s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord);"));
+ s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord);"));
+
+ s.append(TString("vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod);"));
+ s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod);"));
+ s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod);"));
+ s.append(TString("vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);"));
+
+ return s;
+}
+
+//============================================================================
+//
+// Prototypes for built-in functions seen by fragment shaders only.
+//
+//============================================================================
+static TString BuiltInFunctionsFragment(const ShBuiltInResources& resources)
+{
+ TString s;
+
+ //
+ // Texture Functions.
+ //
+ s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord);"));
+ s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord);"));
+
+ s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord, float bias);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias);"));
+ s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias);"));
+ s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord, float bias);"));
+
+ if (resources.OES_standard_derivatives) {
+ s.append(TString("float dFdx(float p);"));
+ s.append(TString("vec2 dFdx(vec2 p);"));
+ s.append(TString("vec3 dFdx(vec3 p);"));
+ s.append(TString("vec4 dFdx(vec4 p);"));
+
+ s.append(TString("float dFdy(float p);"));
+ s.append(TString("vec2 dFdy(vec2 p);"));
+ s.append(TString("vec3 dFdy(vec3 p);"));
+ s.append(TString("vec4 dFdy(vec4 p);"));
+
+ s.append(TString("float fwidth(float p);"));
+ s.append(TString("vec2 fwidth(vec2 p);"));
+ s.append(TString("vec3 fwidth(vec3 p);"));
+ s.append(TString("vec4 fwidth(vec4 p);"));
+ }
+
+ return s;
+}
+
+//============================================================================
+//
+// Standard uniforms.
+//
+//============================================================================
+static TString StandardUniforms()
+{
+ TString s;
+
+ //
+ // Depth range in window coordinates
+ //
+ s.append(TString("struct gl_DepthRangeParameters {"));
+ s.append(TString(" highp float near;")); // n
+ s.append(TString(" highp float far;")); // f
+ s.append(TString(" highp float diff;")); // f - n
+ s.append(TString("};"));
+ s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;"));
+
+ return s;
+}
+
+//============================================================================
+//
+// Default precision for vertex shaders.
+//
+//============================================================================
+static TString DefaultPrecisionVertex()
+{
+ TString s;
+
+ s.append(TString("precision highp int;"));
+ s.append(TString("precision highp float;"));
+
+ return s;
+}
+
+//============================================================================
+//
+// Default precision for fragment shaders.
+//
+//============================================================================
+static TString DefaultPrecisionFragment()
+{
+ TString s;
+
+ s.append(TString("precision mediump int;"));
+ // No default precision for float in fragment shaders
+
+ return s;
+}
+
+//============================================================================
+//
+// Implementation dependent built-in constants.
+//
+//============================================================================
+static TString BuiltInConstants(const ShBuiltInResources &resources)
+{
+ TStringStream s;
+
+ s << "const int gl_MaxVertexAttribs = " << resources.MaxVertexAttribs << ";";
+ s << "const int gl_MaxVertexUniformVectors = " << resources.MaxVertexUniformVectors << ";";
+
+ s << "const int gl_MaxVaryingVectors = " << resources.MaxVaryingVectors << ";";
+ s << "const int gl_MaxVertexTextureImageUnits = " << resources.MaxVertexTextureImageUnits << ";";
+ s << "const int gl_MaxCombinedTextureImageUnits = " << resources.MaxCombinedTextureImageUnits << ";";
+ s << "const int gl_MaxTextureImageUnits = " << resources.MaxTextureImageUnits << ";";
+ s << "const int gl_MaxFragmentUniformVectors = " << resources.MaxFragmentUniformVectors << ";";
+ s << "const int gl_MaxDrawBuffers = " << resources.MaxDrawBuffers << ";";
+
+ return s.str();
+}
+
+void TBuiltIns::initialize(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources)
+{
+ switch (type) {
+ case SH_FRAGMENT_SHADER:
+ builtInStrings.push_back(DefaultPrecisionFragment());
+ builtInStrings.push_back(BuiltInFunctionsCommon());
+ builtInStrings.push_back(BuiltInFunctionsFragment(resources));
+ builtInStrings.push_back(StandardUniforms());
+ break;
+
+ case SH_VERTEX_SHADER:
+ builtInStrings.push_back(DefaultPrecisionVertex());
+ builtInStrings.push_back(BuiltInFunctionsCommon());
+ builtInStrings.push_back(BuiltInFunctionsVertex(resources));
+ builtInStrings.push_back(StandardUniforms());
+ break;
+
+ default: assert(false && "Language not supported");
+ }
+
+ builtInStrings.push_back(BuiltInConstants(resources));
+}
+
+void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources,
+ TSymbolTable& symbolTable)
+{
+ //
+ // First, insert some special built-in variables that are not in
+ // the built-in header files.
+ //
+ switch(type) {
+ case SH_FRAGMENT_SHADER:
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EbpMedium, EvqFragCoord, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EbpUndefined, EvqFrontFacing, 1)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EbpMedium, EvqFragColor, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EbpMedium, EvqFragData, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EbpMedium, EvqPointCoord, 2)));
+ break;
+
+ case SH_VERTEX_SHADER:
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EbpHigh, EvqPosition, 4)));
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EbpMedium, EvqPointSize, 1)));
+ break;
+
+ default: assert(false && "Language not supported");
+ }
+
+ //
+ // Next, identify which built-ins from the already loaded headers have
+ // a mapping to an operator. Those that are not identified as such are
+ // expected to be resolved through a library of functions, versus as
+ // operations.
+ //
+ symbolTable.relateToOperator("not", EOpVectorLogicalNot);
+
+ symbolTable.relateToOperator("matrixCompMult", EOpMul);
+
+ symbolTable.relateToOperator("equal", EOpVectorEqual);
+ symbolTable.relateToOperator("notEqual", EOpVectorNotEqual);
+ symbolTable.relateToOperator("lessThan", EOpLessThan);
+ symbolTable.relateToOperator("greaterThan", EOpGreaterThan);
+ symbolTable.relateToOperator("lessThanEqual", EOpLessThanEqual);
+ symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual);
+
+ symbolTable.relateToOperator("radians", EOpRadians);
+ symbolTable.relateToOperator("degrees", EOpDegrees);
+ symbolTable.relateToOperator("sin", EOpSin);
+ symbolTable.relateToOperator("cos", EOpCos);
+ symbolTable.relateToOperator("tan", EOpTan);
+ symbolTable.relateToOperator("asin", EOpAsin);
+ symbolTable.relateToOperator("acos", EOpAcos);
+ symbolTable.relateToOperator("atan", EOpAtan);
+
+ symbolTable.relateToOperator("pow", EOpPow);
+ symbolTable.relateToOperator("exp2", EOpExp2);
+ symbolTable.relateToOperator("log", EOpLog);
+ symbolTable.relateToOperator("exp", EOpExp);
+ symbolTable.relateToOperator("log2", EOpLog2);
+ symbolTable.relateToOperator("sqrt", EOpSqrt);
+ symbolTable.relateToOperator("inversesqrt", EOpInverseSqrt);
+
+ symbolTable.relateToOperator("abs", EOpAbs);
+ symbolTable.relateToOperator("sign", EOpSign);
+ symbolTable.relateToOperator("floor", EOpFloor);
+ symbolTable.relateToOperator("ceil", EOpCeil);
+ symbolTable.relateToOperator("fract", EOpFract);
+ symbolTable.relateToOperator("mod", EOpMod);
+ symbolTable.relateToOperator("min", EOpMin);
+ symbolTable.relateToOperator("max", EOpMax);
+ symbolTable.relateToOperator("clamp", EOpClamp);
+ symbolTable.relateToOperator("mix", EOpMix);
+ symbolTable.relateToOperator("step", EOpStep);
+ symbolTable.relateToOperator("smoothstep", EOpSmoothStep);
+
+ symbolTable.relateToOperator("length", EOpLength);
+ symbolTable.relateToOperator("distance", EOpDistance);
+ symbolTable.relateToOperator("dot", EOpDot);
+ symbolTable.relateToOperator("cross", EOpCross);
+ symbolTable.relateToOperator("normalize", EOpNormalize);
+ symbolTable.relateToOperator("faceforward", EOpFaceForward);
+ symbolTable.relateToOperator("reflect", EOpReflect);
+ symbolTable.relateToOperator("refract", EOpRefract);
+
+ symbolTable.relateToOperator("any", EOpAny);
+ symbolTable.relateToOperator("all", EOpAll);
+
+ // Map language-specific operators.
+ switch(type) {
+ case SH_VERTEX_SHADER:
+ break;
+ case SH_FRAGMENT_SHADER:
+ if (resources.OES_standard_derivatives) {
+ symbolTable.relateToOperator("dFdx", EOpDFdx);
+ symbolTable.relateToOperator("dFdy", EOpDFdy);
+ symbolTable.relateToOperator("fwidth", EOpFwidth);
+
+ symbolTable.relateToExtension("dFdx", "GL_OES_standard_derivatives");
+ symbolTable.relateToExtension("dFdy", "GL_OES_standard_derivatives");
+ symbolTable.relateToExtension("fwidth", "GL_OES_standard_derivatives");
+ }
+ break;
+ default: break;
+ }
+
+ // Finally add resource-specific variables.
+ switch(type) {
+ case SH_FRAGMENT_SHADER: {
+ // Set up gl_FragData. The array size.
+ TType fragData(EbtFloat, EbpMedium, EvqFragColor, 4, false, true);
+ fragData.setArraySize(resources.MaxDrawBuffers);
+ symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData));
+ }
+ break;
+ default: break;
+ }
+}
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extBehavior)
+{
+ if (resources.OES_standard_derivatives)
+ extBehavior["GL_OES_standard_derivatives"] = EBhDisable;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Initialize.h b/Source/ThirdParty/ANGLE/src/compiler/Initialize.h
new file mode 100644
index 000000000..8b0adc6b4
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/Initialize.h
@@ -0,0 +1,35 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _INITIALIZE_INCLUDED_
+#define _INITIALIZE_INCLUDED_
+
+#include "compiler/Common.h"
+#include "compiler/ShHandle.h"
+#include "compiler/SymbolTable.h"
+
+typedef TVector<TString> TBuiltInStrings;
+
+class TBuiltIns {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+
+ void initialize(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources);
+ const TBuiltInStrings& getBuiltInStrings() { return builtInStrings; }
+
+protected:
+ TBuiltInStrings builtInStrings;
+};
+
+void IdentifyBuiltIns(ShShaderType type, ShShaderSpec spec,
+ const ShBuiltInResources& resources,
+ TSymbolTable& symbolTable);
+
+void InitExtensionBehavior(const ShBuiltInResources& resources,
+ TExtensionBehavior& extensionBehavior);
+
+#endif // _INITIALIZE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.cpp b/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.cpp
new file mode 100644
index 000000000..8763cfeea
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.cpp
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/InitializeDll.h"
+
+#include "compiler/InitializeGlobals.h"
+#include "compiler/InitializeParseContext.h"
+#include "compiler/osinclude.h"
+
+OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+
+bool InitProcess()
+{
+ if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) {
+ //
+ // Function is re-entrant.
+ //
+ return true;
+ }
+
+ ThreadInitializeIndex = OS_AllocTLSIndex();
+
+ if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitProcess(): Failed to allocate TLS area for init flag");
+ return false;
+ }
+
+
+ if (!InitializePoolIndex()) {
+ assert(0 && "InitProcess(): Failed to initalize global pool");
+ return false;
+ }
+
+ if (!InitializeParseContextIndex()) {
+ assert(0 && "InitProcess(): Failed to initalize parse context");
+ return false;
+ }
+
+ return InitThread();
+}
+
+bool DetachProcess()
+{
+ bool success = true;
+
+ if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
+ return true;
+
+ success = DetachThread();
+
+ if (!FreeParseContextIndex())
+ success = false;
+
+ FreePoolIndex();
+
+ OS_FreeTLSIndex(ThreadInitializeIndex);
+ ThreadInitializeIndex = OS_INVALID_TLS_INDEX;
+
+ return success;
+}
+
+bool InitThread()
+{
+ //
+ // This function is re-entrant
+ //
+ if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitThread(): Process hasn't been initalised.");
+ return false;
+ }
+
+ if (OS_GetTLSValue(ThreadInitializeIndex) != 0)
+ return true;
+
+ InitializeGlobalPools();
+
+ if (!InitializeGlobalParseContext())
+ return false;
+
+ if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) {
+ assert(0 && "InitThread(): Unable to set init flag.");
+ return false;
+ }
+
+ return true;
+}
+
+bool DetachThread()
+{
+ bool success = true;
+
+ if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX)
+ return true;
+
+ //
+ // Function is re-entrant and this thread may not have been initalised.
+ //
+ if (OS_GetTLSValue(ThreadInitializeIndex) != 0) {
+ if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) {
+ assert(0 && "DetachThread(): Unable to clear init flag.");
+ success = false;
+ }
+
+ if (!FreeParseContext())
+ success = false;
+
+ FreeGlobalPools();
+ }
+
+ return success;
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.h b/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.h
new file mode 100644
index 000000000..857238eea
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/InitializeDll.h
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef __INITIALIZEDLL_H
+#define __INITIALIZEDLL_H
+
+bool InitProcess();
+bool DetachProcess();
+
+bool InitThread();
+bool DetachThread();
+
+#endif // __INITIALIZEDLL_H
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeGlobals.h b/Source/ThirdParty/ANGLE/src/compiler/InitializeGlobals.h
new file mode 100644
index 000000000..842a45281
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/InitializeGlobals.h
@@ -0,0 +1,15 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __INITIALIZE_GLOBALS_INCLUDED_
+#define __INITIALIZE_GLOBALS_INCLUDED_
+
+void InitializeGlobalPools();
+void FreeGlobalPools();
+bool InitializePoolIndex();
+void FreePoolIndex();
+
+#endif // __INITIALIZE_GLOBALS_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.h b/Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.h
new file mode 100644
index 000000000..760fd09d5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/InitializeParseContext.h
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_
+
+bool InitializeParseContextIndex();
+bool FreeParseContextIndex();
+
+bool InitializeGlobalParseContext();
+bool FreeParseContext();
+
+#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/IntermTraverse.cpp b/Source/ThirdParty/ANGLE/src/compiler/IntermTraverse.cpp
new file mode 100644
index 000000000..a13877f18
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/IntermTraverse.cpp
@@ -0,0 +1,293 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+
+//
+// Traverse the intermediate representation tree, and
+// call a node type specific function for each node.
+// Done recursively through the member function Traverse().
+// Node types can be skipped if their function to call is 0,
+// but their subtree will still be traversed.
+// Nodes with children can have their whole subtree skipped
+// if preVisit is turned on and the type specific function
+// returns false.
+//
+// preVisit, postVisit, and rightToLeft control what order
+// nodes are visited in.
+//
+
+//
+// Traversal functions for terminals are straighforward....
+//
+void TIntermSymbol::traverse(TIntermTraverser* it)
+{
+ it->visitSymbol(this);
+}
+
+void TIntermConstantUnion::traverse(TIntermTraverser* it)
+{
+ it->visitConstantUnion(this);
+}
+
+//
+// Traverse a binary node.
+//
+void TIntermBinary::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ //
+ // visit the node before children if pre-visiting.
+ //
+ if(it->preVisit)
+ {
+ visit = it->visitBinary(PreVisit, this);
+ }
+
+ //
+ // Visit the children, in the right order.
+ //
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ if(right)
+ {
+ right->traverse(it);
+ }
+
+ if(it->inVisit)
+ {
+ visit = it->visitBinary(InVisit, this);
+ }
+
+ if(visit && left)
+ {
+ left->traverse(it);
+ }
+ }
+ else
+ {
+ if(left)
+ {
+ left->traverse(it);
+ }
+
+ if(it->inVisit)
+ {
+ visit = it->visitBinary(InVisit, this);
+ }
+
+ if(visit && right)
+ {
+ right->traverse(it);
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ //
+ // Visit the node after the children, if requested and the traversal
+ // hasn't been cancelled yet.
+ //
+ if(visit && it->postVisit)
+ {
+ it->visitBinary(PostVisit, this);
+ }
+}
+
+//
+// Traverse a unary node. Same comments in binary node apply here.
+//
+void TIntermUnary::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitUnary(PreVisit, this);
+
+ if (visit) {
+ it->incrementDepth();
+ operand->traverse(it);
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitUnary(PostVisit, this);
+}
+
+//
+// Traverse an aggregate node. Same comments in binary node apply here.
+//
+void TIntermAggregate::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if(it->preVisit)
+ {
+ visit = it->visitAggregate(PreVisit, this);
+ }
+
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ for(TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++)
+ {
+ (*sit)->traverse(it);
+
+ if(visit && it->inVisit)
+ {
+ if(*sit != sequence.front())
+ {
+ visit = it->visitAggregate(InVisit, this);
+ }
+ }
+ }
+ }
+ else
+ {
+ for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ (*sit)->traverse(it);
+
+ if(visit && it->inVisit)
+ {
+ if(*sit != sequence.back())
+ {
+ visit = it->visitAggregate(InVisit, this);
+ }
+ }
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ if(visit && it->postVisit)
+ {
+ it->visitAggregate(PostVisit, this);
+ }
+}
+
+//
+// Traverse a selection node. Same comments in binary node apply here.
+//
+void TIntermSelection::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitSelection(PreVisit, this);
+
+ if (visit) {
+ it->incrementDepth();
+ if (it->rightToLeft) {
+ if (falseBlock)
+ falseBlock->traverse(it);
+ if (trueBlock)
+ trueBlock->traverse(it);
+ condition->traverse(it);
+ } else {
+ condition->traverse(it);
+ if (trueBlock)
+ trueBlock->traverse(it);
+ if (falseBlock)
+ falseBlock->traverse(it);
+ }
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitSelection(PostVisit, this);
+}
+
+//
+// Traverse a loop node. Same comments in binary node apply here.
+//
+void TIntermLoop::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if(it->preVisit)
+ {
+ visit = it->visitLoop(PreVisit, this);
+ }
+
+ if(visit)
+ {
+ it->incrementDepth();
+
+ if(it->rightToLeft)
+ {
+ if(expr)
+ {
+ expr->traverse(it);
+ }
+
+ if(body)
+ {
+ body->traverse(it);
+ }
+
+ if(cond)
+ {
+ cond->traverse(it);
+ }
+ }
+ else
+ {
+ if(cond)
+ {
+ cond->traverse(it);
+ }
+
+ if(body)
+ {
+ body->traverse(it);
+ }
+
+ if(expr)
+ {
+ expr->traverse(it);
+ }
+ }
+
+ it->decrementDepth();
+ }
+
+ if(visit && it->postVisit)
+ {
+ it->visitLoop(PostVisit, this);
+ }
+}
+
+//
+// Traverse a branch node. Same comments in binary node apply here.
+//
+void TIntermBranch::traverse(TIntermTraverser* it)
+{
+ bool visit = true;
+
+ if (it->preVisit)
+ visit = it->visitBranch(PreVisit, this);
+
+ if (visit && expression) {
+ it->incrementDepth();
+ expression->traverse(it);
+ it->decrementDepth();
+ }
+
+ if (visit && it->postVisit)
+ it->visitBranch(PostVisit, this);
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Intermediate.cpp b/Source/ThirdParty/ANGLE/src/compiler/Intermediate.cpp
new file mode 100644
index 000000000..e1e8da25a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/Intermediate.cpp
@@ -0,0 +1,1454 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Build the intermediate representation.
+//
+
+#include <float.h>
+#include <limits.h>
+#include <algorithm>
+
+#include "compiler/localintermediate.h"
+#include "compiler/QualifierAlive.h"
+#include "compiler/RemoveTree.h"
+
+bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray);
+
+static TPrecision GetHigherPrecision( TPrecision left, TPrecision right ){
+ return left > right ? left : right;
+}
+
+const char* getOperatorString(TOperator op) {
+ switch (op) {
+ case EOpInitialize: return "=";
+ case EOpAssign: return "=";
+ case EOpAddAssign: return "+=";
+ case EOpSubAssign: return "-=";
+ case EOpDivAssign: return "/=";
+
+ // Fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign: return "*=";
+
+ // Fall-through.
+ case EOpIndexDirect:
+ case EOpIndexIndirect: return "[]";
+
+ case EOpIndexDirectStruct: return ".";
+ case EOpVectorSwizzle: return ".";
+ case EOpAdd: return "+";
+ case EOpSub: return "-";
+ case EOpMul: return "*";
+ case EOpDiv: return "/";
+ case EOpMod: UNIMPLEMENTED(); break;
+ case EOpEqual: return "==";
+ case EOpNotEqual: return "!=";
+ case EOpLessThan: return "<";
+ case EOpGreaterThan: return ">";
+ case EOpLessThanEqual: return "<=";
+ case EOpGreaterThanEqual: return ">=";
+
+ // Fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix: return "*";
+
+ case EOpLogicalOr: return "||";
+ case EOpLogicalXor: return "^^";
+ case EOpLogicalAnd: return "&&";
+ case EOpNegative: return "-";
+ case EOpVectorLogicalNot: return "not";
+ case EOpLogicalNot: return "!";
+ case EOpPostIncrement: return "++";
+ case EOpPostDecrement: return "--";
+ case EOpPreIncrement: return "++";
+ case EOpPreDecrement: return "--";
+
+ // Fall-through.
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool: return "bool";
+
+ // Fall-through.
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat: return "float";
+
+ // Fall-through.
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt: return "int";
+
+ case EOpRadians: return "radians";
+ case EOpDegrees: return "degrees";
+ case EOpSin: return "sin";
+ case EOpCos: return "cos";
+ case EOpTan: return "tan";
+ case EOpAsin: return "asin";
+ case EOpAcos: return "acos";
+ case EOpAtan: return "atan";
+ case EOpExp: return "exp";
+ case EOpLog: return "log";
+ case EOpExp2: return "exp2";
+ case EOpLog2: return "log2";
+ case EOpSqrt: return "sqrt";
+ case EOpInverseSqrt: return "inversesqrt";
+ case EOpAbs: return "abs";
+ case EOpSign: return "sign";
+ case EOpFloor: return "floor";
+ case EOpCeil: return "ceil";
+ case EOpFract: return "fract";
+ case EOpLength: return "length";
+ case EOpNormalize: return "normalize";
+ case EOpDFdx: return "dFdx";
+ case EOpDFdy: return "dFdy";
+ case EOpFwidth: return "fwidth";
+ case EOpAny: return "any";
+ case EOpAll: return "all";
+
+ default: break;
+ }
+ return "";
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// First set of functions are to help build the intermediate representation.
+// These functions are not member functions of the nodes.
+// They are called from parser productions.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Add a terminal node for an identifier in an expression.
+//
+// Returns the added node.
+//
+TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line)
+{
+ TIntermSymbol* node = new TIntermSymbol(id, name, type);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Connect two nodes with a new parent that does a binary operation on the nodes.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TSymbolTable& symbolTable)
+{
+ switch (op) {
+ case EOpEqual:
+ case EOpNotEqual:
+ if (left->isArray())
+ return 0;
+ break;
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if (left->isMatrix() || left->isArray() || left->isVector() || left->getBasicType() == EbtStruct) {
+ return 0;
+ }
+ break;
+ case EOpLogicalOr:
+ case EOpLogicalXor:
+ case EOpLogicalAnd:
+ if (left->getBasicType() != EbtBool || left->isMatrix() || left->isArray() || left->isVector()) {
+ return 0;
+ }
+ break;
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpMul:
+ if (left->getBasicType() == EbtStruct || left->getBasicType() == EbtBool)
+ return 0;
+ default: break;
+ }
+
+ //
+ // First try converting the children to compatible types.
+ //
+ if (left->getType().getStruct() && right->getType().getStruct()) {
+ if (left->getType() != right->getType())
+ return 0;
+ } else {
+ TIntermTyped* child = addConversion(op, left->getType(), right);
+ if (child)
+ right = child;
+ else {
+ child = addConversion(op, right->getType(), left);
+ if (child)
+ left = child;
+ else
+ return 0;
+ }
+ }
+
+ //
+ // Need a new node holding things together then. Make
+ // one and promote it to the right type.
+ //
+ TIntermBinary* node = new TIntermBinary(op);
+ if (line == 0)
+ line = right->getLine();
+ node->setLine(line);
+
+ node->setLeft(left);
+ node->setRight(right);
+ if (!node->promote(infoSink))
+ return 0;
+
+ //
+ // See if we can fold constants.
+ //
+ TIntermTyped* typedReturnNode = 0;
+ TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion();
+ TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion();
+ if (leftTempConstant && rightTempConstant) {
+ typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink);
+
+ if (typedReturnNode)
+ return typedReturnNode;
+ }
+
+ return node;
+}
+
+//
+// Connect two nodes through an assignment.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
+{
+ //
+ // Like adding binary math, except the conversion can only go
+ // from right to left.
+ //
+ TIntermBinary* node = new TIntermBinary(op);
+ if (line == 0)
+ line = left->getLine();
+ node->setLine(line);
+
+ TIntermTyped* child = addConversion(op, left->getType(), right);
+ if (child == 0)
+ return 0;
+
+ node->setLeft(left);
+ node->setRight(child);
+ if (! node->promote(infoSink))
+ return 0;
+
+ return node;
+}
+
+//
+// Connect two nodes through an index operator, where the left node is the base
+// of an array or struct, and the right node is a direct or indirect offset.
+//
+// Returns the added node.
+// The caller should set the type of the returned node.
+//
+TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line)
+{
+ TIntermBinary* node = new TIntermBinary(op);
+ if (line == 0)
+ line = index->getLine();
+ node->setLine(line);
+ node->setLeft(base);
+ node->setRight(index);
+
+ // caller should set the type
+
+ return node;
+}
+
+//
+// Add one node as the parent of another that it operates on.
+//
+// Returns the added node.
+//
+TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable)
+{
+ TIntermUnary* node;
+ TIntermTyped* child = childNode->getAsTyped();
+
+ if (child == 0) {
+ infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line);
+ return 0;
+ }
+
+ switch (op) {
+ case EOpLogicalNot:
+ if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) {
+ return 0;
+ }
+ break;
+
+ case EOpPostIncrement:
+ case EOpPreIncrement:
+ case EOpPostDecrement:
+ case EOpPreDecrement:
+ case EOpNegative:
+ if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
+ return 0;
+ default: break;
+ }
+
+ //
+ // Do we need to promote the operand?
+ //
+ // Note: Implicit promotions were removed from the language.
+ //
+ TBasicType newType = EbtVoid;
+ switch (op) {
+ case EOpConstructInt: newType = EbtInt; break;
+ case EOpConstructBool: newType = EbtBool; break;
+ case EOpConstructFloat: newType = EbtFloat; break;
+ default: break;
+ }
+
+ if (newType != EbtVoid) {
+ child = addConversion(op, TType(newType, child->getPrecision(), EvqTemporary,
+ child->getNominalSize(),
+ child->isMatrix(),
+ child->isArray()),
+ child);
+ if (child == 0)
+ return 0;
+ }
+
+ //
+ // For constructors, we are now done, it's all in the conversion.
+ //
+ switch (op) {
+ case EOpConstructInt:
+ case EOpConstructBool:
+ case EOpConstructFloat:
+ return child;
+ default: break;
+ }
+
+ TIntermConstantUnion *childTempConstant = 0;
+ if (child->getAsConstantUnion())
+ childTempConstant = child->getAsConstantUnion();
+
+ //
+ // Make a new node for the operator.
+ //
+ node = new TIntermUnary(op);
+ if (line == 0)
+ line = child->getLine();
+ node->setLine(line);
+ node->setOperand(child);
+
+ if (! node->promote(infoSink))
+ return 0;
+
+ if (childTempConstant) {
+ TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink);
+
+ if (newChild)
+ return newChild;
+ }
+
+ return node;
+}
+
+//
+// This is the safe way to change the operator on an aggregate, as it
+// does lots of error checking and fixing. Especially for establishing
+// a function call's operation on it's set of parameters. Sequences
+// of instructions are also aggregates, but they just direnctly set
+// their operator to EOpSequence.
+//
+// Returns an aggregate node, which could be the one passed in if
+// it was already an aggregate.
+//
+TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line)
+{
+ TIntermAggregate* aggNode;
+
+ //
+ // Make sure we have an aggregate. If not turn it into one.
+ //
+ if (node) {
+ aggNode = node->getAsAggregate();
+ if (aggNode == 0 || aggNode->getOp() != EOpNull) {
+ //
+ // Make an aggregate containing this node.
+ //
+ aggNode = new TIntermAggregate();
+ aggNode->getSequence().push_back(node);
+ if (line == 0)
+ line = node->getLine();
+ }
+ } else
+ aggNode = new TIntermAggregate();
+
+ //
+ // Set the operator.
+ //
+ aggNode->setOp(op);
+ if (line != 0)
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Convert one type to another.
+//
+// Returns the node representing the conversion, which could be the same
+// node passed in if no conversion was needed.
+//
+// Return 0 if a conversion can't be done.
+//
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
+{
+ //
+ // Does the base type allow operation?
+ //
+ switch (node->getBasicType()) {
+ case EbtVoid:
+ case EbtSampler2D:
+ case EbtSamplerCube:
+ return 0;
+ default: break;
+ }
+
+ //
+ // Otherwise, if types are identical, no problem
+ //
+ if (type == node->getType())
+ return node;
+
+ //
+ // If one's a structure, then no conversions.
+ //
+ if (type.getStruct() || node->getType().getStruct())
+ return 0;
+
+ //
+ // If one's an array, then no conversions.
+ //
+ if (type.isArray() || node->getType().isArray())
+ return 0;
+
+ TBasicType promoteTo;
+
+ switch (op) {
+ //
+ // Explicit conversions
+ //
+ case EOpConstructBool:
+ promoteTo = EbtBool;
+ break;
+ case EOpConstructFloat:
+ promoteTo = EbtFloat;
+ break;
+ case EOpConstructInt:
+ promoteTo = EbtInt;
+ break;
+ default:
+ //
+ // implicit conversions were removed from the language.
+ //
+ if (type.getBasicType() != node->getType().getBasicType())
+ return 0;
+ //
+ // Size and structure could still differ, but that's
+ // handled by operator promotion.
+ //
+ return node;
+ }
+
+ if (node->getAsConstantUnion()) {
+
+ return (promoteConstantUnion(promoteTo, node->getAsConstantUnion()));
+ } else {
+
+ //
+ // Add a new newNode for the conversion.
+ //
+ TIntermUnary* newNode = 0;
+
+ TOperator newOp = EOpNull;
+ switch (promoteTo) {
+ case EbtFloat:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToFloat; break;
+ case EbtBool: newOp = EOpConvBoolToFloat; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
+ return 0;
+ }
+ break;
+ case EbtBool:
+ switch (node->getBasicType()) {
+ case EbtInt: newOp = EOpConvIntToBool; break;
+ case EbtFloat: newOp = EOpConvFloatToBool; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getBasicType()) {
+ case EbtBool: newOp = EOpConvBoolToInt; break;
+ case EbtFloat: newOp = EOpConvFloatToInt; break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine());
+ return 0;
+ }
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine());
+ return 0;
+ }
+
+ TType type(promoteTo, node->getPrecision(), EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray());
+ newNode = new TIntermUnary(newOp, type);
+ newNode->setLine(node->getLine());
+ newNode->setOperand(node);
+
+ return newNode;
+ }
+}
+
+//
+// Safe way to combine two nodes into an aggregate. Works with null pointers,
+// a node that's not a aggregate yet, etc.
+//
+// Returns the resulting aggregate, unless 0 was passed in for
+// both existing nodes.
+//
+TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line)
+{
+ if (left == 0 && right == 0)
+ return 0;
+
+ TIntermAggregate* aggNode = 0;
+ if (left)
+ aggNode = left->getAsAggregate();
+ if (!aggNode || aggNode->getOp() != EOpNull) {
+ aggNode = new TIntermAggregate;
+ if (left)
+ aggNode->getSequence().push_back(left);
+ }
+
+ if (right)
+ aggNode->getSequence().push_back(right);
+
+ if (line != 0)
+ aggNode->setLine(line);
+
+ return aggNode;
+}
+
+//
+// Turn an existing node into an aggregate.
+//
+// Returns an aggregate, unless 0 was passed in for the existing node.
+//
+TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line)
+{
+ if (node == 0)
+ return 0;
+
+ TIntermAggregate* aggNode = new TIntermAggregate;
+ aggNode->getSequence().push_back(node);
+
+ if (line != 0)
+ aggNode->setLine(line);
+ else
+ aggNode->setLine(node->getLine());
+
+ return aggNode;
+}
+
+//
+// For "if" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are in the
+// nodePair.
+//
+// Returns the selection node created.
+//
+TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line)
+{
+ //
+ // For compile time constant selections, prune the code and
+ // test now.
+ //
+
+ if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) {
+ if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getBConst())
+ return nodePair.node1;
+ else
+ return nodePair.node2;
+ }
+
+ TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2);
+ node->setLine(line);
+
+ return node;
+}
+
+
+TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line)
+{
+ if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) {
+ return right;
+ } else {
+ TIntermTyped *commaAggregate = growAggregate(left, right, line);
+ commaAggregate->getAsAggregate()->setOp(EOpComma);
+ commaAggregate->setType(right->getType());
+ commaAggregate->getTypePointer()->setQualifier(EvqTemporary);
+ return commaAggregate;
+ }
+}
+
+//
+// For "?:" test nodes. There are three children; a condition,
+// a true path, and a false path. The two paths are specified
+// as separate parameters.
+//
+// Returns the selection node created, or 0 if one could not be.
+//
+TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line)
+{
+ //
+ // Get compatible types.
+ //
+ TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock);
+ if (child)
+ falseBlock = child;
+ else {
+ child = addConversion(EOpSequence, falseBlock->getType(), trueBlock);
+ if (child)
+ trueBlock = child;
+ else
+ return 0;
+ }
+
+ //
+ // See if all the operands are constant, then fold it otherwise not.
+ //
+
+ if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) {
+ if (cond->getAsConstantUnion()->getUnionArrayPointer()->getBConst())
+ return trueBlock;
+ else
+ return falseBlock;
+ }
+
+ //
+ // Make a selection node.
+ //
+ TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType());
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Constant terminal nodes. Has a union that contains bool, float or int constants
+//
+// Returns the constant union node created.
+//
+
+TIntermConstantUnion* TIntermediate::addConstantUnion(ConstantUnion* unionArrayPointer, const TType& t, TSourceLoc line)
+{
+ TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t);
+ node->setLine(line);
+
+ return node;
+}
+
+TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line)
+{
+
+ TIntermAggregate* node = new TIntermAggregate(EOpSequence);
+
+ node->setLine(line);
+ TIntermConstantUnion* constIntNode;
+ TIntermSequence &sequenceVector = node->getSequence();
+ ConstantUnion* unionArray;
+
+ for (int i = 0; i < fields.num; i++) {
+ unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.offsets[i]);
+ constIntNode = addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), line);
+ sequenceVector.push_back(constIntNode);
+ }
+
+ return node;
+}
+
+//
+// Create loop nodes.
+//
+TIntermNode* TIntermediate::addLoop(TLoopType type, TIntermNode* init, TIntermTyped* cond, TIntermTyped* expr, TIntermNode* body, TSourceLoc line)
+{
+ TIntermNode* node = new TIntermLoop(type, init, cond, expr, body);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// Add branches.
+//
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line)
+{
+ return addBranch(branchOp, 0, line);
+}
+
+TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line)
+{
+ TIntermBranch* node = new TIntermBranch(branchOp, expression);
+ node->setLine(line);
+
+ return node;
+}
+
+//
+// This is to be executed once the final root is put on top by the parsing
+// process.
+//
+bool TIntermediate::postProcess(TIntermNode* root)
+{
+ if (root == 0)
+ return true;
+
+ //
+ // First, finish off the top level sequence, if any
+ //
+ TIntermAggregate* aggRoot = root->getAsAggregate();
+ if (aggRoot && aggRoot->getOp() == EOpNull)
+ aggRoot->setOp(EOpSequence);
+
+ return true;
+}
+
+//
+// This deletes the tree.
+//
+void TIntermediate::remove(TIntermNode* root)
+{
+ if (root)
+ RemoveAllTreeNodes(root);
+}
+
+////////////////////////////////////////////////////////////////
+//
+// Member functions of the nodes used for building the tree.
+//
+////////////////////////////////////////////////////////////////
+
+//
+// Say whether or not an operation node changes the value of a variable.
+//
+// Returns true if state is modified.
+//
+bool TIntermOperator::modifiesState() const
+{
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ case EOpAssign:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ case EOpDivAssign:
+ return true;
+ default:
+ return false;
+ }
+}
+
+//
+// returns true if the operator is for one of the constructors
+//
+bool TIntermOperator::isConstructor() const
+{
+ switch (op) {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ case EOpConstructStruct:
+ return true;
+ default:
+ return false;
+ }
+}
+//
+// Make sure the type of a unary operator is appropriate for its
+// combination of operation and operand type.
+//
+// Returns false in nothing makes sense.
+//
+bool TIntermUnary::promote(TInfoSink&)
+{
+ switch (op) {
+ case EOpLogicalNot:
+ if (operand->getBasicType() != EbtBool)
+ return false;
+ break;
+ case EOpNegative:
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ if (operand->getBasicType() == EbtBool)
+ return false;
+ break;
+
+ // operators for built-ins are already type checked against their prototype
+ case EOpAny:
+ case EOpAll:
+ case EOpVectorLogicalNot:
+ return true;
+
+ default:
+ if (operand->getBasicType() != EbtFloat)
+ return false;
+ }
+
+ setType(operand->getType());
+
+ return true;
+}
+
+//
+// Establishes the type of the resultant operation, as well as
+// makes the operator the correct one for the operands.
+//
+// Returns false if operator can't work on operands.
+//
+bool TIntermBinary::promote(TInfoSink& infoSink)
+{
+ // This function only handles scalars, vectors, and matrices.
+ if (left->isArray() || right->isArray()) {
+ infoSink.info.message(EPrefixInternalError, "Invalid operation for arrays", getLine());
+ return false;
+ }
+
+ // GLSL ES 2.0 does not support implicit type casting.
+ // So the basic type should always match.
+ if (left->getBasicType() != right->getBasicType())
+ return false;
+
+ //
+ // Base assumption: just make the type the same as the left
+ // operand. Then only deviations from this need be coded.
+ //
+ setType(left->getType());
+
+ // The result gets promoted to the highest precision.
+ TPrecision higherPrecision = GetHigherPrecision(left->getPrecision(), right->getPrecision());
+ getTypePointer()->setPrecision(higherPrecision);
+
+ // Binary operations results in temporary variables unless both
+ // operands are const.
+ if (left->getQualifier() != EvqConst || right->getQualifier() != EvqConst) {
+ getTypePointer()->setQualifier(EvqTemporary);
+ }
+
+ int size = std::max(left->getNominalSize(), right->getNominalSize());
+
+ //
+ // All scalars. Code after this test assumes this case is removed!
+ //
+ if (size == 1) {
+ switch (op) {
+ //
+ // Promote to conditional
+ //
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ //
+ // And and Or operate on conditionals
+ //
+ case EOpLogicalAnd:
+ case EOpLogicalOr:
+ // Both operands must be of type bool.
+ if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool)
+ return false;
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ default:
+ break;
+ }
+ return true;
+ }
+
+ // If we reach here, at least one of the operands is vector or matrix.
+ // The other operand could be a scalar, vector, or matrix.
+ // Are the sizes compatible?
+ //
+ if (left->getNominalSize() != right->getNominalSize()) {
+ // If the nominal size of operands do not match:
+ // One of them must be scalar.
+ if (left->getNominalSize() != 1 && right->getNominalSize() != 1)
+ return false;
+ // Operator cannot be of type pure assignment.
+ if (op == EOpAssign || op == EOpInitialize)
+ return false;
+ }
+
+ //
+ // Can these two operands be combined?
+ //
+ TBasicType basicType = left->getBasicType();
+ switch (op) {
+ case EOpMul:
+ if (!left->isMatrix() && right->isMatrix()) {
+ if (left->isVector())
+ op = EOpVectorTimesMatrix;
+ else {
+ op = EOpMatrixTimesScalar;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, true));
+ }
+ } else if (left->isMatrix() && !right->isMatrix()) {
+ if (right->isVector()) {
+ op = EOpMatrixTimesVector;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ } else {
+ op = EOpMatrixTimesScalar;
+ }
+ } else if (left->isMatrix() && right->isMatrix()) {
+ op = EOpMatrixTimesMatrix;
+ } else if (!left->isMatrix() && !right->isMatrix()) {
+ if (left->isVector() && right->isVector()) {
+ // leave as component product
+ } else if (left->isVector() || right->isVector()) {
+ op = EOpVectorTimesScalar;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ }
+ } else {
+ infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
+ return false;
+ }
+ break;
+ case EOpMulAssign:
+ if (!left->isMatrix() && right->isMatrix()) {
+ if (left->isVector())
+ op = EOpVectorTimesMatrixAssign;
+ else {
+ return false;
+ }
+ } else if (left->isMatrix() && !right->isMatrix()) {
+ if (right->isVector()) {
+ return false;
+ } else {
+ op = EOpMatrixTimesScalarAssign;
+ }
+ } else if (left->isMatrix() && right->isMatrix()) {
+ op = EOpMatrixTimesMatrixAssign;
+ } else if (!left->isMatrix() && !right->isMatrix()) {
+ if (left->isVector() && right->isVector()) {
+ // leave as component product
+ } else if (left->isVector() || right->isVector()) {
+ if (! left->isVector())
+ return false;
+ op = EOpVectorTimesScalarAssign;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, false));
+ }
+ } else {
+ infoSink.info.message(EPrefixInternalError, "Missing elses", getLine());
+ return false;
+ }
+ break;
+
+ case EOpAssign:
+ case EOpInitialize:
+ case EOpAdd:
+ case EOpSub:
+ case EOpDiv:
+ case EOpAddAssign:
+ case EOpSubAssign:
+ case EOpDivAssign:
+ if ((left->isMatrix() && right->isVector()) ||
+ (left->isVector() && right->isMatrix()))
+ return false;
+ setType(TType(basicType, higherPrecision, EvqTemporary, size, left->isMatrix() || right->isMatrix()));
+ break;
+
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ if ((left->isMatrix() && right->isVector()) ||
+ (left->isVector() && right->isMatrix()))
+ return false;
+ setType(TType(EbtBool, EbpUndefined));
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool CompareStruct(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
+{
+ const TTypeList* fields = leftNodeType.getStruct();
+
+ size_t structSize = fields->size();
+ int index = 0;
+
+ for (size_t j = 0; j < structSize; j++) {
+ int size = (*fields)[j].type->getObjectSize();
+ for (int i = 0; i < size; i++) {
+ if ((*fields)[j].type->getBasicType() == EbtStruct) {
+ if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index]))
+ return false;
+ } else {
+ if (leftUnionArray[index] != rightUnionArray[index])
+ return false;
+ index++;
+ }
+
+ }
+ }
+ return true;
+}
+
+bool CompareStructure(const TType& leftNodeType, ConstantUnion* rightUnionArray, ConstantUnion* leftUnionArray)
+{
+ if (leftNodeType.isArray()) {
+ TType typeWithoutArrayness = leftNodeType;
+ typeWithoutArrayness.clearArrayness();
+
+ int arraySize = leftNodeType.getArraySize();
+
+ for (int i = 0; i < arraySize; ++i) {
+ int offset = typeWithoutArrayness.getObjectSize() * i;
+ if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset]))
+ return false;
+ }
+ } else
+ return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
+
+ return true;
+}
+
+//
+// The fold functions see if an operation on a constant can be done in place,
+// without generating run-time code.
+//
+// Returns the node to keep using, which may or may not be the node passed in.
+//
+
+TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink)
+{
+ ConstantUnion *unionArray = getUnionArrayPointer();
+ int objectSize = getType().getObjectSize();
+
+ if (constantNode) { // binary operations
+ TIntermConstantUnion *node = constantNode->getAsConstantUnion();
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ TType returnType = getType();
+
+ // for a case like float f = 1.2 + vec4(2,3,4,5);
+ if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) {
+ rightUnionArray = new ConstantUnion[objectSize];
+ for (int i = 0; i < objectSize; ++i)
+ rightUnionArray[i] = *node->getUnionArrayPointer();
+ returnType = getType();
+ } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) {
+ // for a case like float f = vec4(2,3,4,5) + 1.2;
+ unionArray = new ConstantUnion[constantNode->getType().getObjectSize()];
+ for (int i = 0; i < constantNode->getType().getObjectSize(); ++i)
+ unionArray[i] = *getUnionArrayPointer();
+ returnType = node->getType();
+ objectSize = constantNode->getType().getObjectSize();
+ }
+
+ ConstantUnion* tempConstArray = 0;
+ TIntermConstantUnion *tempNode;
+
+ bool boolNodeFlag = false;
+ switch(op) {
+ case EOpAdd:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] + rightUnionArray[i];
+ }
+ break;
+ case EOpSub:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] - rightUnionArray[i];
+ }
+ break;
+
+ case EOpMul:
+ case EOpVectorTimesScalar:
+ case EOpMatrixTimesScalar:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] * rightUnionArray[i];
+ }
+ break;
+ case EOpMatrixTimesMatrix:
+ if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine());
+ return 0;
+ }
+ {// support MSVC++6.0
+ int size = getNominalSize();
+ tempConstArray = new ConstantUnion[size*size];
+ for (int row = 0; row < size; row++) {
+ for (int column = 0; column < size; column++) {
+ tempConstArray[size * column + row].setFConst(0.0f);
+ for (int i = 0; i < size; i++) {
+ tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst()));
+ }
+ }
+ }
+ }
+ break;
+ case EOpDiv:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++) {
+ switch (getType().getBasicType()) {
+ case EbtFloat:
+ if (rightUnionArray[i] == 0.0f) {
+ infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
+ tempConstArray[i].setFConst(FLT_MAX);
+ } else
+ tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst());
+ break;
+
+ case EbtInt:
+ if (rightUnionArray[i] == 0) {
+ infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine());
+ tempConstArray[i].setIConst(INT_MAX);
+ } else
+ tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst());
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine());
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case EOpMatrixTimesVector:
+ if (node->getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine());
+ return 0;
+ }
+ tempConstArray = new ConstantUnion[getNominalSize()];
+
+ {// support MSVC++6.0
+ for (int size = getNominalSize(), i = 0; i < size; i++) {
+ tempConstArray[i].setFConst(0.0f);
+ for (int j = 0; j < size; j++) {
+ tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst()));
+ }
+ }
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, node->getType());
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ case EOpVectorTimesMatrix:
+ if (getType().getBasicType() != EbtFloat) {
+ infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine());
+ return 0;
+ }
+
+ tempConstArray = new ConstantUnion[getNominalSize()];
+ {// support MSVC++6.0
+ for (int size = getNominalSize(), i = 0; i < size; i++) {
+ tempConstArray[i].setFConst(0.0f);
+ for (int j = 0; j < size; j++) {
+ tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst()));
+ }
+ }
+ }
+ break;
+
+ case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] && rightUnionArray[i];
+ }
+ break;
+
+ case EOpLogicalOr: // this code is written for possible future use, will not get executed currently
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ tempConstArray[i] = unionArray[i] || rightUnionArray[i];
+ }
+ break;
+
+ case EOpLogicalXor:
+ tempConstArray = new ConstantUnion[objectSize];
+ {// support MSVC++6.0
+ for (int i = 0; i < objectSize; i++)
+ switch (getType().getBasicType()) {
+ case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break;
+ default: assert(false && "Default missing");
+ }
+ }
+ break;
+
+ case EOpLessThan:
+ assert(objectSize == 1);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(*unionArray < *rightUnionArray);
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ case EOpGreaterThan:
+ assert(objectSize == 1);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(*unionArray > *rightUnionArray);
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ case EOpLessThanEqual:
+ {
+ assert(objectSize == 1);
+ ConstantUnion constant;
+ constant.setBConst(*unionArray > *rightUnionArray);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(!constant.getBConst());
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ }
+ case EOpGreaterThanEqual:
+ {
+ assert(objectSize == 1);
+ ConstantUnion constant;
+ constant.setBConst(*unionArray < *rightUnionArray);
+ tempConstArray = new ConstantUnion[1];
+ tempConstArray->setBConst(!constant.getBConst());
+ returnType = TType(EbtBool, EbpUndefined, EvqConst);
+ break;
+ }
+
+ case EOpEqual:
+ if (getType().getBasicType() == EbtStruct) {
+ if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
+ boolNodeFlag = true;
+ } else {
+ for (int i = 0; i < objectSize; i++) {
+ if (unionArray[i] != rightUnionArray[i]) {
+ boolNodeFlag = true;
+ break; // break out of for loop
+ }
+ }
+ }
+
+ tempConstArray = new ConstantUnion[1];
+ if (!boolNodeFlag) {
+ tempConstArray->setBConst(true);
+ }
+ else {
+ tempConstArray->setBConst(false);
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ case EOpNotEqual:
+ if (getType().getBasicType() == EbtStruct) {
+ if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray))
+ boolNodeFlag = true;
+ } else {
+ for (int i = 0; i < objectSize; i++) {
+ if (unionArray[i] == rightUnionArray[i]) {
+ boolNodeFlag = true;
+ break; // break out of for loop
+ }
+ }
+ }
+
+ tempConstArray = new ConstantUnion[1];
+ if (!boolNodeFlag) {
+ tempConstArray->setBConst(true);
+ }
+ else {
+ tempConstArray->setBConst(false);
+ }
+
+ tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EbpUndefined, EvqConst));
+ tempNode->setLine(getLine());
+
+ return tempNode;
+
+ default:
+ infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine());
+ return 0;
+ }
+ tempNode = new TIntermConstantUnion(tempConstArray, returnType);
+ tempNode->setLine(getLine());
+
+ return tempNode;
+ } else {
+ //
+ // Do unary operations
+ //
+ TIntermConstantUnion *newNode = 0;
+ ConstantUnion* tempConstArray = new ConstantUnion[objectSize];
+ for (int i = 0; i < objectSize; i++) {
+ switch(op) {
+ case EOpNegative:
+ switch (getType().getBasicType()) {
+ case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break;
+ case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+ return 0;
+ }
+ break;
+ case EOpLogicalNot: // this code is written for possible future use, will not get executed currently
+ switch (getType().getBasicType()) {
+ case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine());
+ return 0;
+ }
+ break;
+ default:
+ return 0;
+ }
+ }
+ newNode = new TIntermConstantUnion(tempConstArray, getType());
+ newNode->setLine(getLine());
+ return newNode;
+ }
+
+ return this;
+}
+
+TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node)
+{
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ int size = node->getType().getObjectSize();
+
+ ConstantUnion *leftUnionArray = new ConstantUnion[size];
+
+ for (int i=0; i < size; i++) {
+
+ switch (promoteTo) {
+ case EbtFloat:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getIConst()));
+ break;
+ case EbtBool:
+ leftUnionArray[i].setFConst(static_cast<float>(rightUnionArray[i].getBConst()));
+ break;
+ case EbtFloat:
+ leftUnionArray[i] = rightUnionArray[i];
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
+ return 0;
+ }
+ break;
+ case EbtInt:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i] = rightUnionArray[i];
+ break;
+ case EbtBool:
+ leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getBConst()));
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setIConst(static_cast<int>(rightUnionArray[i].getFConst()));
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
+ return 0;
+ }
+ break;
+ case EbtBool:
+ switch (node->getType().getBasicType()) {
+ case EbtInt:
+ leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0);
+ break;
+ case EbtBool:
+ leftUnionArray[i] = rightUnionArray[i];
+ break;
+ case EbtFloat:
+ leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f);
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine());
+ return 0;
+ }
+
+ break;
+ default:
+ infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine());
+ return 0;
+ }
+
+ }
+
+ const TType& t = node->getType();
+
+ return addConstantUnion(leftUnionArray, TType(promoteTo, t.getPrecision(), t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine());
+}
+
+void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable)
+{
+ assert(!pragmaTable);
+ pragmaTable = new TPragmaTable();
+ *pragmaTable = pTable;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/MMap.h b/Source/ThirdParty/ANGLE/src/compiler/MMap.h
new file mode 100644
index 000000000..a30867151
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/MMap.h
@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _MMAP_INCLUDED_
+#define _MMAP_INCLUDED_
+
+//
+// Encapsulate memory mapped files
+//
+
+class TMMap {
+public:
+ TMMap(const char* fileName) :
+ fSize(-1), // -1 is the error value returned by GetFileSize()
+ fp(NULL),
+ fBuff(0) // 0 is the error value returned by MapViewOfFile()
+ {
+ if ((fp = fopen(fileName, "r")) == NULL)
+ return;
+ char c = getc(fp);
+ fSize = 0;
+ while (c != EOF) {
+ fSize++;
+ c = getc(fp);
+ }
+ if (c == EOF)
+ fSize++;
+ rewind(fp);
+ fBuff = (char*)malloc(sizeof(char) * fSize);
+ int count = 0;
+ c = getc(fp);
+ while (c != EOF) {
+ fBuff[count++] = c;
+ c = getc(fp);
+ }
+ fBuff[count++] = c;
+ }
+
+ char* getData() { return fBuff; }
+ int getSize() { return fSize; }
+
+ ~TMMap() {
+ if (fp != NULL)
+ fclose(fp);
+ }
+
+private:
+ int fSize; // size of file to map in
+ FILE *fp;
+ char* fBuff; // the actual data;
+};
+
+#endif // _MMAP_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.cpp b/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.cpp
new file mode 100644
index 000000000..c9b6a12b2
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/MapLongVariableNames.h"
+
+namespace {
+
+TString mapLongName(int id, const TString& name, bool isVarying)
+{
+ ASSERT(name.size() > MAX_IDENTIFIER_NAME_SIZE);
+ TStringStream stream;
+ stream << "webgl_";
+ if (isVarying)
+ stream << "v";
+ stream << id << "_";
+ stream << name.substr(0, MAX_IDENTIFIER_NAME_SIZE - stream.str().size());
+ return stream.str();
+}
+
+} // anonymous namespace
+
+MapLongVariableNames::MapLongVariableNames(
+ TMap<TString, TString>& varyingLongNameMap)
+ : mVaryingLongNameMap(varyingLongNameMap)
+{
+}
+
+void MapLongVariableNames::visitSymbol(TIntermSymbol* symbol)
+{
+ ASSERT(symbol != NULL);
+ if (symbol->getSymbol().size() > MAX_IDENTIFIER_NAME_SIZE) {
+ switch (symbol->getQualifier()) {
+ case EvqVaryingIn:
+ case EvqVaryingOut:
+ case EvqInvariantVaryingIn:
+ case EvqInvariantVaryingOut:
+ symbol->setSymbol(
+ mapVaryingLongName(symbol->getSymbol()));
+ break;
+ default:
+ symbol->setSymbol(
+ mapLongName(symbol->getId(), symbol->getSymbol(), false));
+ break;
+ };
+ }
+}
+
+void MapLongVariableNames::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool MapLongVariableNames::visitBinary(Visit, TIntermBinary*)
+{
+ return true;
+}
+
+bool MapLongVariableNames::visitUnary(Visit, TIntermUnary*)
+{
+ return true;
+}
+
+bool MapLongVariableNames::visitSelection(Visit, TIntermSelection*)
+{
+ return true;
+}
+
+bool MapLongVariableNames::visitAggregate(Visit, TIntermAggregate*)
+{
+ return true;
+}
+
+bool MapLongVariableNames::visitLoop(Visit, TIntermLoop* node)
+{
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ return true;
+}
+
+bool MapLongVariableNames::visitBranch(Visit, TIntermBranch*)
+{
+ return true;
+}
+
+TString MapLongVariableNames::mapVaryingLongName(const TString& name)
+{
+ TMap<TString, TString>::const_iterator it = mVaryingLongNameMap.find(name);
+ if (it != mVaryingLongNameMap.end())
+ return (*it).second;
+
+ int id = mVaryingLongNameMap.size();
+ TString mappedName = mapLongName(id, name, true);
+ mVaryingLongNameMap.insert(
+ TMap<TString, TString>::value_type(name, mappedName));
+ return mappedName;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.h b/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.h
new file mode 100644
index 000000000..540909ea9
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/MapLongVariableNames.h
@@ -0,0 +1,39 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_MAP_LONG_VARIABLE_NAMES_H_
+#define COMPILER_MAP_LONG_VARIABLE_NAMES_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/intermediate.h"
+#include "compiler/VariableInfo.h"
+
+// This size does not include '\0' in the end.
+#define MAX_IDENTIFIER_NAME_SIZE 32
+
+// Traverses intermediate tree to map attributes and uniforms names that are
+// longer than MAX_IDENTIFIER_NAME_SIZE to MAX_IDENTIFIER_NAME_SIZE.
+class MapLongVariableNames : public TIntermTraverser {
+public:
+ MapLongVariableNames(TMap<TString, TString>& varyingLongNameMap);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+private:
+ TString mapVaryingLongName(const TString& name);
+
+ TMap<TString, TString>& mVaryingLongNameMap;
+};
+
+#endif // COMPILER_MAP_LONG_VARIABLE_NAMES_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.cpp
new file mode 100644
index 000000000..64ee92d44
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.cpp
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputESSL.h"
+
+TOutputESSL::TOutputESSL(TInfoSinkBase& objSink)
+ : TOutputGLSLBase(objSink)
+{
+}
+
+bool TOutputESSL::writeVariablePrecision(TPrecision precision)
+{
+ if (precision == EbpUndefined)
+ return false;
+
+ TInfoSinkBase& out = objSink();
+ out << getPrecisionString(precision);
+ return true;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.h b/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.h
new file mode 100644
index 000000000..4fa73c804
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/OutputESSL.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_
+#define CROSSCOMPILERGLSL_OUTPUTESSL_H_
+
+#include "compiler/OutputGLSLBase.h"
+
+class TOutputESSL : public TOutputGLSLBase
+{
+public:
+ TOutputESSL(TInfoSinkBase& objSink);
+
+protected:
+ virtual bool writeVariablePrecision(TPrecision precision);
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.cpp
new file mode 100644
index 000000000..dd31b4b58
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.cpp
@@ -0,0 +1,17 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputGLSL.h"
+
+TOutputGLSL::TOutputGLSL(TInfoSinkBase& objSink)
+ : TOutputGLSLBase(objSink)
+{
+}
+
+bool TOutputGLSL::writeVariablePrecision(TPrecision)
+{
+ return false;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.h
new file mode 100644
index 000000000..0fe2356eb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSL.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_
+#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_
+
+#include "compiler/OutputGLSLBase.h"
+
+class TOutputGLSL : public TOutputGLSLBase
+{
+public:
+ TOutputGLSL(TInfoSinkBase& objSink);
+
+protected:
+ virtual bool writeVariablePrecision(TPrecision);
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.cpp b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.cpp
new file mode 100644
index 000000000..a0feb07eb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.cpp
@@ -0,0 +1,707 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputGLSLBase.h"
+#include "compiler/debug.h"
+
+namespace
+{
+TString getTypeName(const TType& type)
+{
+ TInfoSinkBase out;
+ if (type.isMatrix())
+ {
+ out << "mat";
+ out << type.getNominalSize();
+ }
+ else if (type.isVector())
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat: out << "vec"; break;
+ case EbtInt: out << "ivec"; break;
+ case EbtBool: out << "bvec"; break;
+ default: UNREACHABLE(); break;
+ }
+ out << type.getNominalSize();
+ }
+ else
+ {
+ if (type.getBasicType() == EbtStruct)
+ out << type.getTypeName();
+ else
+ out << type.getBasicString();
+ }
+ return TString(out.c_str());
+}
+
+TString arrayBrackets(const TType& type)
+{
+ ASSERT(type.isArray());
+ TInfoSinkBase out;
+ out << "[" << type.getArraySize() << "]";
+ return TString(out.c_str());
+}
+
+bool isSingleStatement(TIntermNode* node) {
+ if (const TIntermAggregate* aggregate = node->getAsAggregate())
+ {
+ return (aggregate->getOp() != EOpFunction) &&
+ (aggregate->getOp() != EOpSequence);
+ }
+ else if (const TIntermSelection* selection = node->getAsSelectionNode())
+ {
+ // Ternary operators are usually part of an assignment operator.
+ // This handles those rare cases in which they are all by themselves.
+ return selection->usesTernaryOperator();
+ }
+ else if (node->getAsLoopNode())
+ {
+ return false;
+ }
+ return true;
+}
+} // namespace
+
+TOutputGLSLBase::TOutputGLSLBase(TInfoSinkBase& objSink)
+ : TIntermTraverser(true, true, true),
+ mObjSink(objSink),
+ mDeclaringVariables(false)
+{
+}
+
+void TOutputGLSLBase::writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr)
+{
+ TInfoSinkBase& out = objSink();
+ if (visit == PreVisit && preStr)
+ {
+ out << preStr;
+ }
+ else if (visit == InVisit && inStr)
+ {
+ out << inStr;
+ }
+ else if (visit == PostVisit && postStr)
+ {
+ out << postStr;
+ }
+}
+
+void TOutputGLSLBase::writeVariableType(const TType& type)
+{
+ TInfoSinkBase& out = objSink();
+ TQualifier qualifier = type.getQualifier();
+ // TODO(alokp): Validate qualifier for variable declarations.
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal))
+ out << type.getQualifierString() << " ";
+ // Declare the struct if we have not done so already.
+ if ((type.getBasicType() == EbtStruct) &&
+ (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end()))
+ {
+ out << "struct " << type.getTypeName() << "{\n";
+ const TTypeList* structure = type.getStruct();
+ ASSERT(structure != NULL);
+ for (size_t i = 0; i < structure->size(); ++i)
+ {
+ const TType* fieldType = (*structure)[i].type;
+ ASSERT(fieldType != NULL);
+ if (writeVariablePrecision(fieldType->getPrecision()))
+ out << " ";
+ out << getTypeName(*fieldType) << " " << fieldType->getFieldName();
+ if (fieldType->isArray())
+ out << arrayBrackets(*fieldType);
+ out << ";\n";
+ }
+ out << "}";
+ mDeclaredStructs.insert(type.getTypeName());
+ }
+ else
+ {
+ if (writeVariablePrecision(type.getPrecision()))
+ out << " ";
+ out << getTypeName(type);
+ }
+}
+
+void TOutputGLSLBase::writeFunctionParameters(const TIntermSequence& args)
+{
+ TInfoSinkBase& out = objSink();
+ for (TIntermSequence::const_iterator iter = args.begin();
+ iter != args.end(); ++iter)
+ {
+ const TIntermSymbol* arg = (*iter)->getAsSymbolNode();
+ ASSERT(arg != NULL);
+
+ const TType& type = arg->getType();
+ writeVariableType(type);
+
+ const TString& name = arg->getSymbol();
+ if (!name.empty())
+ out << " " << name;
+ if (type.isArray())
+ out << arrayBrackets(type);
+
+ // Put a comma if this is not the last argument.
+ if (iter != args.end() - 1)
+ out << ", ";
+ }
+}
+
+const ConstantUnion* TOutputGLSLBase::writeConstantUnion(const TType& type,
+ const ConstantUnion* pConstUnion)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ out << type.getTypeName() << "(";
+ const TTypeList* structure = type.getStruct();
+ ASSERT(structure != NULL);
+ for (size_t i = 0; i < structure->size(); ++i)
+ {
+ const TType* fieldType = (*structure)[i].type;
+ ASSERT(fieldType != NULL);
+ pConstUnion = writeConstantUnion(*fieldType, pConstUnion);
+ if (i != structure->size() - 1) out << ", ";
+ }
+ out << ")";
+ }
+ else
+ {
+ int size = type.getObjectSize();
+ bool writeType = size > 1;
+ if (writeType) out << getTypeName(type) << "(";
+ for (int i = 0; i < size; ++i, ++pConstUnion)
+ {
+ switch (pConstUnion->getType())
+ {
+ case EbtFloat: out << pConstUnion->getFConst(); break;
+ case EbtInt: out << pConstUnion->getIConst(); break;
+ case EbtBool: out << pConstUnion->getBConst(); break;
+ default: UNREACHABLE();
+ }
+ if (i != size - 1) out << ", ";
+ }
+ if (writeType) out << ")";
+ }
+ return pConstUnion;
+}
+
+void TOutputGLSLBase::visitSymbol(TIntermSymbol* node)
+{
+ TInfoSinkBase& out = objSink();
+ if (mLoopUnroll.NeedsToReplaceSymbolWithValue(node))
+ out << mLoopUnroll.GetLoopIndexValue(node);
+ else
+ out << node->getSymbol();
+
+ if (mDeclaringVariables && node->getType().isArray())
+ out << arrayBrackets(node->getType());
+}
+
+void TOutputGLSLBase::visitConstantUnion(TIntermConstantUnion* node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+bool TOutputGLSLBase::visitBinary(Visit visit, TIntermBinary* node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase& out = objSink();
+ switch (node->getOp())
+ {
+ case EOpInitialize:
+ if (visit == InVisit)
+ {
+ out << " = ";
+ // RHS of initialize is not being declared.
+ mDeclaringVariables = false;
+ }
+ break;
+ case EOpAssign: writeTriplet(visit, "(", " = ", ")"); break;
+ case EOpAddAssign: writeTriplet(visit, "(", " += ", ")"); break;
+ case EOpSubAssign: writeTriplet(visit, "(", " -= ", ")"); break;
+ case EOpDivAssign: writeTriplet(visit, "(", " /= ", ")"); break;
+ // Notice the fall-through.
+ case EOpMulAssign:
+ case EOpVectorTimesMatrixAssign:
+ case EOpVectorTimesScalarAssign:
+ case EOpMatrixTimesScalarAssign:
+ case EOpMatrixTimesMatrixAssign:
+ writeTriplet(visit, "(", " *= ", ")");
+ break;
+
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ writeTriplet(visit, NULL, "[", "]");
+ break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ out << ".";
+ // TODO(alokp): ASSERT
+ out << node->getType().getFieldName();
+ visitChildren = false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+ TIntermAggregate* rightChild = node->getRight()->getAsAggregate();
+ TIntermSequence& sequence = rightChild->getSequence();
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); ++sit)
+ {
+ TIntermConstantUnion* element = (*sit)->getAsConstantUnion();
+ ASSERT(element->getBasicType() == EbtInt);
+ ASSERT(element->getNominalSize() == 1);
+ const ConstantUnion& data = element->getUnionArrayPointer()[0];
+ ASSERT(data.getType() == EbtInt);
+ switch (data.getIConst())
+ {
+ case 0: out << "x"; break;
+ case 1: out << "y"; break;
+ case 2: out << "z"; break;
+ case 3: out << "w"; break;
+ default: UNREACHABLE(); break;
+ }
+ }
+ visitChildren = false;
+ }
+ break;
+
+ case EOpAdd: writeTriplet(visit, "(", " + ", ")"); break;
+ case EOpSub: writeTriplet(visit, "(", " - ", ")"); break;
+ case EOpMul: writeTriplet(visit, "(", " * ", ")"); break;
+ case EOpDiv: writeTriplet(visit, "(", " / ", ")"); break;
+ case EOpMod: UNIMPLEMENTED(); break;
+ case EOpEqual: writeTriplet(visit, "(", " == ", ")"); break;
+ case EOpNotEqual: writeTriplet(visit, "(", " != ", ")"); break;
+ case EOpLessThan: writeTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: writeTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: writeTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: writeTriplet(visit, "(", " >= ", ")"); break;
+
+ // Notice the fall-through.
+ case EOpVectorTimesScalar:
+ case EOpVectorTimesMatrix:
+ case EOpMatrixTimesVector:
+ case EOpMatrixTimesScalar:
+ case EOpMatrixTimesMatrix:
+ writeTriplet(visit, "(", " * ", ")");
+ break;
+
+ case EOpLogicalOr: writeTriplet(visit, "(", " || ", ")"); break;
+ case EOpLogicalXor: writeTriplet(visit, "(", " ^^ ", ")"); break;
+ case EOpLogicalAnd: writeTriplet(visit, "(", " && ", ")"); break;
+ default: UNREACHABLE(); break;
+ }
+
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitUnary(Visit visit, TIntermUnary* node)
+{
+ switch (node->getOp())
+ {
+ case EOpNegative: writeTriplet(visit, "(-", NULL, ")"); break;
+ case EOpVectorLogicalNot: writeTriplet(visit, "not(", NULL, ")"); break;
+ case EOpLogicalNot: writeTriplet(visit, "(!", NULL, ")"); break;
+
+ case EOpPostIncrement: writeTriplet(visit, "(", NULL, "++)"); break;
+ case EOpPostDecrement: writeTriplet(visit, "(", NULL, "--)"); break;
+ case EOpPreIncrement: writeTriplet(visit, "(++", NULL, ")"); break;
+ case EOpPreDecrement: writeTriplet(visit, "(--", NULL, ")"); break;
+
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: writeTriplet(visit, "bool(", NULL, ")"); break;
+ case 2: writeTriplet(visit, "bvec2(", NULL, ")"); break;
+ case 3: writeTriplet(visit, "bvec3(", NULL, ")"); break;
+ case 4: writeTriplet(visit, "bvec4(", NULL, ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: writeTriplet(visit, "float(", NULL, ")"); break;
+ case 2: writeTriplet(visit, "vec2(", NULL, ")"); break;
+ case 3: writeTriplet(visit, "vec3(", NULL, ")"); break;
+ case 4: writeTriplet(visit, "vec4(", NULL, ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: writeTriplet(visit, "int(", NULL, ")"); break;
+ case 2: writeTriplet(visit, "ivec2(", NULL, ")"); break;
+ case 3: writeTriplet(visit, "ivec3(", NULL, ")"); break;
+ case 4: writeTriplet(visit, "ivec4(", NULL, ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+
+ case EOpRadians: writeTriplet(visit, "radians(", NULL, ")"); break;
+ case EOpDegrees: writeTriplet(visit, "degrees(", NULL, ")"); break;
+ case EOpSin: writeTriplet(visit, "sin(", NULL, ")"); break;
+ case EOpCos: writeTriplet(visit, "cos(", NULL, ")"); break;
+ case EOpTan: writeTriplet(visit, "tan(", NULL, ")"); break;
+ case EOpAsin: writeTriplet(visit, "asin(", NULL, ")"); break;
+ case EOpAcos: writeTriplet(visit, "acos(", NULL, ")"); break;
+ case EOpAtan: writeTriplet(visit, "atan(", NULL, ")"); break;
+
+ case EOpExp: writeTriplet(visit, "exp(", NULL, ")"); break;
+ case EOpLog: writeTriplet(visit, "log(", NULL, ")"); break;
+ case EOpExp2: writeTriplet(visit, "exp2(", NULL, ")"); break;
+ case EOpLog2: writeTriplet(visit, "log2(", NULL, ")"); break;
+ case EOpSqrt: writeTriplet(visit, "sqrt(", NULL, ")"); break;
+ case EOpInverseSqrt: writeTriplet(visit, "inversesqrt(", NULL, ")"); break;
+
+ case EOpAbs: writeTriplet(visit, "abs(", NULL, ")"); break;
+ case EOpSign: writeTriplet(visit, "sign(", NULL, ")"); break;
+ case EOpFloor: writeTriplet(visit, "floor(", NULL, ")"); break;
+ case EOpCeil: writeTriplet(visit, "ceil(", NULL, ")"); break;
+ case EOpFract: writeTriplet(visit, "fract(", NULL, ")"); break;
+
+ case EOpLength: writeTriplet(visit, "length(", NULL, ")"); break;
+ case EOpNormalize: writeTriplet(visit, "normalize(", NULL, ")"); break;
+
+ case EOpDFdx: writeTriplet(visit, "dFdx(", NULL, ")"); break;
+ case EOpDFdy: writeTriplet(visit, "dFdy(", NULL, ")"); break;
+ case EOpFwidth: writeTriplet(visit, "fwidth(", NULL, ")"); break;
+
+ case EOpAny: writeTriplet(visit, "any(", NULL, ")"); break;
+ case EOpAll: writeTriplet(visit, "all(", NULL, ")"); break;
+
+ default: UNREACHABLE(); break;
+ }
+
+ return true;
+}
+
+bool TOutputGLSLBase::visitSelection(Visit visit, TIntermSelection* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ if (node->usesTernaryOperator())
+ {
+ // Notice two brackets at the beginning and end. The outer ones
+ // encapsulate the whole ternary expression. This preserves the
+ // order of precedence when ternary expressions are used in a
+ // compound expression, i.e., c = 2 * (a < b ? 1 : 2).
+ out << "((";
+ node->getCondition()->traverse(this);
+ out << ") ? (";
+ node->getTrueBlock()->traverse(this);
+ out << ") : (";
+ node->getFalseBlock()->traverse(this);
+ out << "))";
+ }
+ else
+ {
+ out << "if (";
+ node->getCondition()->traverse(this);
+ out << ")\n";
+
+ incrementDepth();
+ visitCodeBlock(node->getTrueBlock());
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+ visitCodeBlock(node->getFalseBlock());
+ }
+ decrementDepth();
+ }
+ return false;
+}
+
+bool TOutputGLSLBase::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ bool visitChildren = true;
+ TInfoSinkBase& out = objSink();
+ switch (node->getOp())
+ {
+ case EOpSequence: {
+ // Scope the sequences except when at the global scope.
+ if (depth > 0) out << "{\n";
+
+ incrementDepth();
+ const TIntermSequence& sequence = node->getSequence();
+ for (TIntermSequence::const_iterator iter = sequence.begin();
+ iter != sequence.end(); ++iter)
+ {
+ TIntermNode* node = *iter;
+ ASSERT(node != NULL);
+ node->traverse(this);
+
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ decrementDepth();
+
+ // Scope the sequences except when at the global scope.
+ if (depth > 0) out << "}\n";
+ visitChildren = false;
+ break;
+ }
+ case EOpPrototype: {
+ // Function declaration.
+ ASSERT(visit == PreVisit);
+ TString returnType = getTypeName(node->getType());
+ out << returnType << " " << node->getName();
+
+ out << "(";
+ writeFunctionParameters(node->getSequence());
+ out << ")";
+
+ visitChildren = false;
+ break;
+ }
+ case EOpFunction: {
+ // Function definition.
+ ASSERT(visit == PreVisit);
+ writeVariableType(node->getType());
+ out << " " << TFunction::unmangleName(node->getName());
+
+ incrementDepth();
+ // Function definition node contains one or two children nodes
+ // representing function parameters and function body. The latter
+ // is not present in case of empty function bodies.
+ const TIntermSequence& sequence = node->getSequence();
+ ASSERT((sequence.size() == 1) || (sequence.size() == 2));
+ TIntermSequence::const_iterator seqIter = sequence.begin();
+
+ // Traverse function parameters.
+ TIntermAggregate* params = (*seqIter)->getAsAggregate();
+ ASSERT(params != NULL);
+ ASSERT(params->getOp() == EOpParameters);
+ params->traverse(this);
+
+ // Traverse function body.
+ TIntermAggregate* body = ++seqIter != sequence.end() ?
+ (*seqIter)->getAsAggregate() : NULL;
+ visitCodeBlock(body);
+ decrementDepth();
+
+ // Fully processed; no need to visit children.
+ visitChildren = false;
+ break;
+ }
+ case EOpFunctionCall:
+ // Function call.
+ if (visit == PreVisit)
+ {
+ TString functionName = TFunction::unmangleName(node->getName());
+ out << functionName << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ break;
+ case EOpParameters: {
+ // Function parameters.
+ ASSERT(visit == PreVisit);
+ out << "(";
+ writeFunctionParameters(node->getSequence());
+ out << ")";
+ visitChildren = false;
+ break;
+ }
+ case EOpDeclaration: {
+ // Variable declaration.
+ if (visit == PreVisit)
+ {
+ const TIntermSequence& sequence = node->getSequence();
+ const TIntermTyped* variable = sequence.front()->getAsTyped();
+ writeVariableType(variable->getType());
+ out << " ";
+ mDeclaringVariables = true;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ mDeclaringVariables = true;
+ }
+ else
+ {
+ mDeclaringVariables = false;
+ }
+ break;
+ }
+ case EOpConstructFloat: writeTriplet(visit, "float(", NULL, ")"); break;
+ case EOpConstructVec2: writeTriplet(visit, "vec2(", ", ", ")"); break;
+ case EOpConstructVec3: writeTriplet(visit, "vec3(", ", ", ")"); break;
+ case EOpConstructVec4: writeTriplet(visit, "vec4(", ", ", ")"); break;
+ case EOpConstructBool: writeTriplet(visit, "bool(", NULL, ")"); break;
+ case EOpConstructBVec2: writeTriplet(visit, "bvec2(", ", ", ")"); break;
+ case EOpConstructBVec3: writeTriplet(visit, "bvec3(", ", ", ")"); break;
+ case EOpConstructBVec4: writeTriplet(visit, "bvec4(", ", ", ")"); break;
+ case EOpConstructInt: writeTriplet(visit, "int(", NULL, ")"); break;
+ case EOpConstructIVec2: writeTriplet(visit, "ivec2(", ", ", ")"); break;
+ case EOpConstructIVec3: writeTriplet(visit, "ivec3(", ", ", ")"); break;
+ case EOpConstructIVec4: writeTriplet(visit, "ivec4(", ", ", ")"); break;
+ case EOpConstructMat2: writeTriplet(visit, "mat2(", ", ", ")"); break;
+ case EOpConstructMat3: writeTriplet(visit, "mat3(", ", ", ")"); break;
+ case EOpConstructMat4: writeTriplet(visit, "mat4(", ", ", ")"); break;
+ case EOpConstructStruct:
+ if (visit == PreVisit)
+ {
+ const TType& type = node->getType();
+ ASSERT(type.getBasicType() == EbtStruct);
+ out << type.getTypeName() << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ break;
+
+ case EOpLessThan: writeTriplet(visit, "lessThan(", ", ", ")"); break;
+ case EOpGreaterThan: writeTriplet(visit, "greaterThan(", ", ", ")"); break;
+ case EOpLessThanEqual: writeTriplet(visit, "lessThanEqual(", ", ", ")"); break;
+ case EOpGreaterThanEqual: writeTriplet(visit, "greaterThanEqual(", ", ", ")"); break;
+ case EOpVectorEqual: writeTriplet(visit, "equal(", ", ", ")"); break;
+ case EOpVectorNotEqual: writeTriplet(visit, "notEqual(", ", ", ")"); break;
+ case EOpComma: writeTriplet(visit, NULL, ", ", NULL); break;
+
+ case EOpMod: writeTriplet(visit, "mod(", ", ", ")"); break;
+ case EOpPow: writeTriplet(visit, "pow(", ", ", ")"); break;
+ case EOpAtan: writeTriplet(visit, "atan(", ", ", ")"); break;
+ case EOpMin: writeTriplet(visit, "min(", ", ", ")"); break;
+ case EOpMax: writeTriplet(visit, "max(", ", ", ")"); break;
+ case EOpClamp: writeTriplet(visit, "clamp(", ", ", ")"); break;
+ case EOpMix: writeTriplet(visit, "mix(", ", ", ")"); break;
+ case EOpStep: writeTriplet(visit, "step(", ", ", ")"); break;
+ case EOpSmoothStep: writeTriplet(visit, "smoothstep(", ", ", ")"); break;
+
+ case EOpDistance: writeTriplet(visit, "distance(", ", ", ")"); break;
+ case EOpDot: writeTriplet(visit, "dot(", ", ", ")"); break;
+ case EOpCross: writeTriplet(visit, "cross(", ", ", ")"); break;
+ case EOpFaceForward: writeTriplet(visit, "faceforward(", ", ", ")"); break;
+ case EOpReflect: writeTriplet(visit, "reflect(", ", ", ")"); break;
+ case EOpRefract: writeTriplet(visit, "refract(", ", ", ")"); break;
+ case EOpMul: writeTriplet(visit, "matrixCompMult(", ", ", ")"); break;
+
+ default: UNREACHABLE(); break;
+ }
+ return visitChildren;
+}
+
+bool TOutputGLSLBase::visitLoop(Visit visit, TIntermLoop* node)
+{
+ TInfoSinkBase& out = objSink();
+
+ incrementDepth();
+ // Loop header.
+ TLoopType loopType = node->getType();
+ if (loopType == ELoopFor) // for loop
+ {
+ if (!node->getUnrollFlag()) {
+ out << "for (";
+ if (node->getInit())
+ node->getInit()->traverse(this);
+ out << "; ";
+
+ if (node->getCondition())
+ node->getCondition()->traverse(this);
+ out << "; ";
+
+ if (node->getExpression())
+ node->getExpression()->traverse(this);
+ out << ")\n";
+ }
+ }
+ else if (loopType == ELoopWhile) // while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ node->getCondition()->traverse(this);
+ out << ")\n";
+ }
+ else // do-while loop
+ {
+ ASSERT(loopType == ELoopDoWhile);
+ out << "do\n";
+ }
+
+ // Loop body.
+ if (node->getUnrollFlag())
+ {
+ TLoopIndexInfo indexInfo;
+ mLoopUnroll.FillLoopIndexInfo(node, indexInfo);
+ mLoopUnroll.Push(indexInfo);
+ while (mLoopUnroll.SatisfiesLoopCondition())
+ {
+ visitCodeBlock(node->getBody());
+ mLoopUnroll.Step();
+ }
+ mLoopUnroll.Pop();
+ }
+ else
+ {
+ visitCodeBlock(node->getBody());
+ }
+
+ // Loop footer.
+ if (loopType == ELoopDoWhile) // do-while loop
+ {
+ out << "while (";
+ ASSERT(node->getCondition() != NULL);
+ node->getCondition()->traverse(this);
+ out << ");\n";
+ }
+ decrementDepth();
+
+ // No need to visit children. They have been already processed in
+ // this function.
+ return false;
+}
+
+bool TOutputGLSLBase::visitBranch(Visit visit, TIntermBranch* node)
+{
+ switch (node->getFlowOp())
+ {
+ case EOpKill: writeTriplet(visit, "discard", NULL, NULL); break;
+ case EOpBreak: writeTriplet(visit, "break", NULL, NULL); break;
+ case EOpContinue: writeTriplet(visit, "continue", NULL, NULL); break;
+ case EOpReturn: writeTriplet(visit, "return ", NULL, NULL); break;
+ default: UNREACHABLE(); break;
+ }
+
+ return true;
+}
+
+void TOutputGLSLBase::visitCodeBlock(TIntermNode* node) {
+ TInfoSinkBase &out = objSink();
+ if (node != NULL)
+ {
+ node->traverse(this);
+ // Single statements not part of a sequence need to be terminated
+ // with semi-colon.
+ if (isSingleStatement(node))
+ out << ";\n";
+ }
+ else
+ {
+ out << "{\n}\n"; // Empty code block.
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.h b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.h
new file mode 100644
index 000000000..efd0b5fc2
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/OutputGLSLBase.h
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
+#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
+
+#include <set>
+
+#include "compiler/ForLoopUnroll.h"
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+class TOutputGLSLBase : public TIntermTraverser
+{
+public:
+ TOutputGLSLBase(TInfoSinkBase& objSink);
+
+protected:
+ TInfoSinkBase& objSink() { return mObjSink; }
+ void writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr);
+ void writeVariableType(const TType& type);
+ virtual bool writeVariablePrecision(TPrecision precision) = 0;
+ void writeFunctionParameters(const TIntermSequence& args);
+ const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion);
+
+ virtual void visitSymbol(TIntermSymbol* node);
+ virtual void visitConstantUnion(TIntermConstantUnion* node);
+ virtual bool visitBinary(Visit visit, TIntermBinary* node);
+ virtual bool visitUnary(Visit visit, TIntermUnary* node);
+ virtual bool visitSelection(Visit visit, TIntermSelection* node);
+ virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
+ virtual bool visitLoop(Visit visit, TIntermLoop* node);
+ virtual bool visitBranch(Visit visit, TIntermBranch* node);
+
+ void visitCodeBlock(TIntermNode* node);
+
+private:
+ TInfoSinkBase& mObjSink;
+ bool mDeclaringVariables;
+
+ // Structs are declared as the tree is traversed. This set contains all
+ // the structs already declared. It is maintained so that a struct is
+ // declared only once.
+ typedef std::set<TString> DeclaredStructs;
+ DeclaredStructs mDeclaredStructs;
+
+ ForLoopUnroll mLoopUnroll;
+};
+
+#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.cpp
new file mode 100644
index 000000000..afa8f046b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.cpp
@@ -0,0 +1,2349 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/OutputHLSL.h"
+
+#include "compiler/debug.h"
+#include "compiler/InfoSink.h"
+#include "compiler/UnfoldSelect.h"
+#include "compiler/SearchSymbol.h"
+
+#include <stdio.h>
+#include <algorithm>
+
+namespace sh
+{
+// Integer to TString conversion
+TString str(int i)
+{
+ char buffer[20];
+ sprintf(buffer, "%d", i);
+ return buffer;
+}
+
+OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), mContext(context)
+{
+ mUnfoldSelect = new UnfoldSelect(context, this);
+ mInsideFunction = false;
+
+ mUsesTexture2D = false;
+ mUsesTexture2D_bias = false;
+ mUsesTexture2DProj = false;
+ mUsesTexture2DProj_bias = false;
+ mUsesTexture2DProjLod = false;
+ mUsesTexture2DLod = false;
+ mUsesTextureCube = false;
+ mUsesTextureCube_bias = false;
+ mUsesTextureCubeLod = false;
+ mUsesDepthRange = false;
+ mUsesFragCoord = false;
+ mUsesPointCoord = false;
+ mUsesFrontFacing = false;
+ mUsesPointSize = false;
+ mUsesXor = false;
+ mUsesMod1 = false;
+ mUsesMod2 = false;
+ mUsesMod3 = false;
+ mUsesMod4 = false;
+ mUsesFaceforward1 = false;
+ mUsesFaceforward2 = false;
+ mUsesFaceforward3 = false;
+ mUsesFaceforward4 = false;
+ mUsesEqualMat2 = false;
+ mUsesEqualMat3 = false;
+ mUsesEqualMat4 = false;
+ mUsesEqualVec2 = false;
+ mUsesEqualVec3 = false;
+ mUsesEqualVec4 = false;
+ mUsesEqualIVec2 = false;
+ mUsesEqualIVec3 = false;
+ mUsesEqualIVec4 = false;
+ mUsesEqualBVec2 = false;
+ mUsesEqualBVec3 = false;
+ mUsesEqualBVec4 = false;
+ mUsesAtan2 = false;
+
+ mScopeDepth = 0;
+
+ mUniqueIndex = 0;
+}
+
+OutputHLSL::~OutputHLSL()
+{
+ delete mUnfoldSelect;
+}
+
+void OutputHLSL::output()
+{
+ mContext.treeRoot->traverse(this); // Output the body first to determine what has to go in the header
+ header();
+
+ mContext.infoSink.obj << mHeader.c_str();
+ mContext.infoSink.obj << mBody.c_str();
+}
+
+TInfoSinkBase &OutputHLSL::getBodyStream()
+{
+ return mBody;
+}
+
+int OutputHLSL::vectorSize(const TType &type) const
+{
+ int elementSize = type.isMatrix() ? type.getNominalSize() : 1;
+ int arraySize = type.isArray() ? type.getArraySize() : 1;
+
+ return elementSize * arraySize;
+}
+
+void OutputHLSL::header()
+{
+ ShShaderType shaderType = mContext.shaderType;
+ TInfoSinkBase &out = mHeader;
+
+ for (StructDeclarations::iterator structDeclaration = mStructDeclarations.begin(); structDeclaration != mStructDeclarations.end(); structDeclaration++)
+ {
+ out << *structDeclaration;
+ }
+
+ for (Constructors::iterator constructor = mConstructors.begin(); constructor != mConstructors.end(); constructor++)
+ {
+ out << *constructor;
+ }
+
+ if (shaderType == SH_FRAGMENT_SHADER)
+ {
+ TString uniforms;
+ TString varyings;
+
+ TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
+ int semanticIndex = 0;
+
+ for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
+ {
+ const TSymbol *symbol = (*namedSymbol).second;
+ const TString &name = symbol->getName();
+
+ if (symbol->isVariable())
+ {
+ const TVariable *variable = static_cast<const TVariable*>(symbol);
+ const TType &type = variable->getType();
+ TQualifier qualifier = type.getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
+ {
+ uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
+ }
+ }
+ else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
+ {
+ if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
+ {
+ // Program linking depends on this exact format
+ varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+
+ semanticIndex += type.isArray() ? type.getArraySize() : 1;
+ }
+ }
+ else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
+ {
+ // Globals are declared and intialized as an aggregate node
+ }
+ else if (qualifier == EvqConst)
+ {
+ // Constants are repeated as literals where used
+ }
+ else UNREACHABLE();
+ }
+ }
+
+ out << "// Varyings\n";
+ out << varyings;
+ out << "\n"
+ "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n";
+
+ if (mUsesFragCoord)
+ {
+ out << "static float4 gl_FragCoord = float4(0, 0, 0, 0);\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "static float2 gl_PointCoord = float2(0.5, 0.5);\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "static bool gl_FrontFacing = false;\n";
+ }
+
+ out << "\n";
+
+ if (mUsesFragCoord)
+ {
+ out << "uniform float4 dx_Viewport;\n"
+ "uniform float2 dx_Depth;\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "uniform bool dx_PointsOrLines;\n"
+ "uniform bool dx_FrontCCW;\n";
+ }
+
+ out << "\n";
+ out << uniforms;
+ out << "\n";
+
+ // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
+ // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
+ // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
+ // convention, the Y coordinate passed to these functions is adjusted to compensate.
+ //
+ // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
+ //
+ // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
+ // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
+ //
+ // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
+ // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
+ // +Y and -Y faces everywhere else throughout the code.
+
+ if (mUsesTexture2D)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
+ "{\n"
+ " return tex2D(s, float2(t.x, 1 - t.y));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2D_bias)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x, 1 - t.y, 0, bias));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProj)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
+ "{\n"
+ " return tex2Dproj(s, float4(t.x, t.z - t.y, 0, t.z));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
+ "{\n"
+ " return tex2Dproj(s, float4(t.x, t.w - t.y, t.z, t.w));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProj_bias)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x / t.z, 1 - (t.y / t.z), 0, bias));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t, float bias)\n"
+ "{\n"
+ " return tex2Dbias(s, float4(t.x / t.w, 1 - (t.y / t.w), 0, bias));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCube)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
+ "{\n"
+ " return texCUBE(s, float3(t.x, -t.y, t.z));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCube_bias)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t, float bias)\n"
+ "{\n"
+ " return texCUBEbias(s, float4(t.x, -t.y, t.z, bias));\n"
+ "}\n"
+ "\n";
+ }
+ }
+ else // Vertex shader
+ {
+ TString uniforms;
+ TString attributes;
+ TString varyings;
+
+ TSymbolTableLevel *symbols = mContext.symbolTable.getGlobalLevel();
+
+ for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++)
+ {
+ const TSymbol *symbol = (*namedSymbol).second;
+ const TString &name = symbol->getName();
+
+ if (symbol->isVariable())
+ {
+ const TVariable *variable = static_cast<const TVariable*>(symbol);
+ const TType &type = variable->getType();
+ TQualifier qualifier = type.getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ if (mReferencedUniforms.find(name.c_str()) != mReferencedUniforms.end())
+ {
+ uniforms += "uniform " + typeString(type) + " " + decorate(name) + arrayString(type) + ";\n";
+ }
+ }
+ else if (qualifier == EvqAttribute)
+ {
+ if (mReferencedAttributes.find(name.c_str()) != mReferencedAttributes.end())
+ {
+ attributes += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+ }
+ }
+ else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut)
+ {
+ if (mReferencedVaryings.find(name.c_str()) != mReferencedVaryings.end())
+ {
+ // Program linking depends on this exact format
+ varyings += "static " + typeString(type) + " " + decorate(name) + arrayString(type) + " = " + initializer(type) + ";\n";
+ }
+ }
+ else if (qualifier == EvqGlobal || qualifier == EvqTemporary)
+ {
+ // Globals are declared and intialized as an aggregate node
+ }
+ else if (qualifier == EvqConst)
+ {
+ // Constants are repeated as literals where used
+ }
+ else UNREACHABLE();
+ }
+ }
+
+ out << "// Attributes\n";
+ out << attributes;
+ out << "\n"
+ "static float4 gl_Position = float4(0, 0, 0, 0);\n";
+
+ if (mUsesPointSize)
+ {
+ out << "static float gl_PointSize = float(1);\n";
+ }
+
+ out << "\n"
+ "// Varyings\n";
+ out << varyings;
+ out << "\n"
+ "uniform float2 dx_HalfPixelSize;\n"
+ "\n";
+ out << uniforms;
+ out << "\n";
+
+ // The texture fetch functions "flip" the Y coordinate in one way or another. This is because textures are stored
+ // according to the OpenGL convention, i.e. (0, 0) is "bottom left", rather than the D3D convention where (0, 0)
+ // is "top left". Since the HLSL texture fetch functions expect textures to be stored according to the D3D
+ // convention, the Y coordinate passed to these functions is adjusted to compensate.
+ //
+ // The simplest case is texture2D where the mapping is Y -> 1-Y, which maps [0, 1] -> [1, 0].
+ //
+ // The texture2DProj functions are more complicated because the projection divides by either Z or W. For the vec3
+ // case, the mapping is Y -> Z-Y or Y/Z -> 1-Y/Z, which again maps [0, 1] -> [1, 0].
+ //
+ // For cube textures the mapping is Y -> -Y, which maps [-1, 1] -> [1, -1]. This is not sufficient on its own for the
+ // +Y and -Y faces, which are now on the "wrong sides" of the cube. This is compensated for by exchanging the
+ // +Y and -Y faces everywhere else throughout the code.
+
+ if (mUsesTexture2D)
+ {
+ out << "float4 gl_texture2D(sampler2D s, float2 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, 1 - t.y, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DLod)
+ {
+ out << "float4 gl_texture2DLod(sampler2D s, float2 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x, 1 - t.y, 0, lod));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProj)
+ {
+ out << "float4 gl_texture2DProj(sampler2D s, float3 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, 1 - t.y / t.z, 0, 0));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProj(sampler2D s, float4 t)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, 1 - t.y / t.w, 0, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTexture2DProjLod)
+ {
+ out << "float4 gl_texture2DProjLod(sampler2D s, float3 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.z, 1 - t.y / t.z, 0, lod));\n"
+ "}\n"
+ "\n"
+ "float4 gl_texture2DProjLod(sampler2D s, float4 t, float lod)\n"
+ "{\n"
+ " return tex2Dlod(s, float4(t.x / t.w, 1 - t.y / t.w, 0, lod));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCube)
+ {
+ out << "float4 gl_textureCube(samplerCUBE s, float3 t)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, -t.y, t.z, 0));\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesTextureCubeLod)
+ {
+ out << "float4 gl_textureCubeLod(samplerCUBE s, float3 t, float lod)\n"
+ "{\n"
+ " return texCUBElod(s, float4(t.x, -t.y, t.z, lod));\n"
+ "}\n"
+ "\n";
+ }
+ }
+
+ if (mUsesFragCoord)
+ {
+ out << "#define GL_USES_FRAG_COORD\n";
+ }
+
+ if (mUsesPointCoord)
+ {
+ out << "#define GL_USES_POINT_COORD\n";
+ }
+
+ if (mUsesFrontFacing)
+ {
+ out << "#define GL_USES_FRONT_FACING\n";
+ }
+
+ if (mUsesPointSize)
+ {
+ out << "#define GL_USES_POINT_SIZE\n";
+ }
+
+ if (mUsesDepthRange)
+ {
+ out << "struct gl_DepthRangeParameters\n"
+ "{\n"
+ " float near;\n"
+ " float far;\n"
+ " float diff;\n"
+ "};\n"
+ "\n"
+ "uniform float3 dx_DepthRange;"
+ "static gl_DepthRangeParameters gl_DepthRange = {dx_DepthRange.x, dx_DepthRange.y, dx_DepthRange.z};\n"
+ "\n";
+ }
+
+ if (mUsesXor)
+ {
+ out << "bool xor(bool p, bool q)\n"
+ "{\n"
+ " return (p || q) && !(p && q);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod1)
+ {
+ out << "float mod(float x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod2)
+ {
+ out << "float2 mod(float2 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod3)
+ {
+ out << "float3 mod(float3 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesMod4)
+ {
+ out << "float4 mod(float4 x, float y)\n"
+ "{\n"
+ " return x - y * floor(x / y);\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward1)
+ {
+ out << "float faceforward(float N, float I, float Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward2)
+ {
+ out << "float2 faceforward(float2 N, float2 I, float2 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward3)
+ {
+ out << "float3 faceforward(float3 N, float3 I, float3 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesFaceforward4)
+ {
+ out << "float4 faceforward(float4 N, float4 I, float4 Nref)\n"
+ "{\n"
+ " if(dot(Nref, I) >= 0)\n"
+ " {\n"
+ " return -N;\n"
+ " }\n"
+ " else\n"
+ " {\n"
+ " return N;\n"
+ " }\n"
+ "}\n"
+ "\n";
+ }
+
+ if (mUsesEqualMat2)
+ {
+ out << "bool equal(float2x2 m, float2x2 n)\n"
+ "{\n"
+ " return m[0][0] == n[0][0] && m[0][1] == n[0][1] &&\n"
+ " m[1][0] == n[1][0] && m[1][1] == n[1][1];\n"
+ "}\n";
+ }
+
+ if (mUsesEqualMat3)
+ {
+ out << "bool equal(float3x3 m, float3x3 n)\n"
+ "{\n"
+ " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] &&\n"
+ " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] &&\n"
+ " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2];\n"
+ "}\n";
+ }
+
+ if (mUsesEqualMat4)
+ {
+ out << "bool equal(float4x4 m, float4x4 n)\n"
+ "{\n"
+ " return m[0][0] == n[0][0] && m[0][1] == n[0][1] && m[0][2] == n[0][2] && m[0][3] == n[0][3] &&\n"
+ " m[1][0] == n[1][0] && m[1][1] == n[1][1] && m[1][2] == n[1][2] && m[1][3] == n[1][3] &&\n"
+ " m[2][0] == n[2][0] && m[2][1] == n[2][1] && m[2][2] == n[2][2] && m[2][3] == n[2][3] &&\n"
+ " m[3][0] == n[3][0] && m[3][1] == n[3][1] && m[3][2] == n[3][2] && m[3][3] == n[3][3];\n"
+ "}\n";
+ }
+
+ if (mUsesEqualVec2)
+ {
+ out << "bool equal(float2 v, float2 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualVec3)
+ {
+ out << "bool equal(float3 v, float3 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualVec4)
+ {
+ out << "bool equal(float4 v, float4 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualIVec2)
+ {
+ out << "bool equal(int2 v, int2 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualIVec3)
+ {
+ out << "bool equal(int3 v, int3 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualIVec4)
+ {
+ out << "bool equal(int4 v, int4 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualBVec2)
+ {
+ out << "bool equal(bool2 v, bool2 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualBVec3)
+ {
+ out << "bool equal(bool3 v, bool3 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z;\n"
+ "}\n";
+ }
+
+ if (mUsesEqualBVec4)
+ {
+ out << "bool equal(bool4 v, bool4 u)\n"
+ "{\n"
+ " return v.x == u.x && v.y == u.y && v.z == u.z && v.w == u.w;\n"
+ "}\n";
+ }
+
+ if (mUsesAtan2)
+ {
+ out << "float atanyx(float y, float x)\n"
+ "{\n"
+ " if(x == 0 && y == 0) x = 1;\n" // Avoid producing a NaN
+ " return atan2(y, x);\n"
+ "}\n";
+ }
+}
+
+void OutputHLSL::visitSymbol(TIntermSymbol *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ TString name = node->getSymbol();
+
+ if (name == "gl_FragColor")
+ {
+ out << "gl_Color[0]";
+ }
+ else if (name == "gl_FragData")
+ {
+ out << "gl_Color";
+ }
+ else if (name == "gl_DepthRange")
+ {
+ mUsesDepthRange = true;
+ out << name;
+ }
+ else if (name == "gl_FragCoord")
+ {
+ mUsesFragCoord = true;
+ out << name;
+ }
+ else if (name == "gl_PointCoord")
+ {
+ mUsesPointCoord = true;
+ out << name;
+ }
+ else if (name == "gl_FrontFacing")
+ {
+ mUsesFrontFacing = true;
+ out << name;
+ }
+ else if (name == "gl_PointSize")
+ {
+ mUsesPointSize = true;
+ out << name;
+ }
+ else
+ {
+ TQualifier qualifier = node->getQualifier();
+
+ if (qualifier == EvqUniform)
+ {
+ mReferencedUniforms.insert(name.c_str());
+ }
+ else if (qualifier == EvqAttribute)
+ {
+ mReferencedAttributes.insert(name.c_str());
+ }
+ else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut || qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn)
+ {
+ mReferencedVaryings.insert(name.c_str());
+ }
+
+ out << decorate(name);
+ }
+}
+
+bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getOp())
+ {
+ case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break;
+ case EOpInitialize:
+ if (visit == PreVisit)
+ {
+ // GLSL allows to write things like "float x = x;" where a new variable x is defined
+ // and the value of an existing variable x is assigned. HLSL uses C semantics (the
+ // new variable is created before the assignment is evaluated), so we need to convert
+ // this to "float t = x, x = t;".
+
+ TIntermSymbol *symbolNode = node->getLeft()->getAsSymbolNode();
+ TIntermTyped *expression = node->getRight();
+
+ sh::SearchSymbol searchSymbol(symbolNode->getSymbol());
+ expression->traverse(&searchSymbol);
+ bool sameSymbol = searchSymbol.foundMatch();
+
+ if (sameSymbol)
+ {
+ // Type already printed
+ out << "t" + str(mUniqueIndex) + " = ";
+ expression->traverse(this);
+ out << ", ";
+ symbolNode->traverse(this);
+ out << " = t" + str(mUniqueIndex);
+
+ mUniqueIndex++;
+ return false;
+ }
+ }
+ else if (visit == InVisit)
+ {
+ out << " = ";
+ }
+ break;
+ case EOpAddAssign: outputTriplet(visit, "(", " += ", ")"); break;
+ case EOpSubAssign: outputTriplet(visit, "(", " -= ", ")"); break;
+ case EOpMulAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpVectorTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpMatrixTimesScalarAssign: outputTriplet(visit, "(", " *= ", ")"); break;
+ case EOpVectorTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", transpose(";
+ }
+ else
+ {
+ out << ")))";
+ }
+ break;
+ case EOpMatrixTimesMatrixAssign:
+ if (visit == PreVisit)
+ {
+ out << "(";
+ }
+ else if (visit == InVisit)
+ {
+ out << " = mul(";
+ node->getLeft()->traverse(this);
+ out << ", ";
+ }
+ else
+ {
+ out << "))";
+ }
+ break;
+ case EOpDivAssign: outputTriplet(visit, "(", " /= ", ")"); break;
+ case EOpIndexDirect: outputTriplet(visit, "", "[", "]"); break;
+ case EOpIndexIndirect: outputTriplet(visit, "", "[", "]"); break;
+ case EOpIndexDirectStruct:
+ if (visit == InVisit)
+ {
+ out << "." + node->getType().getFieldName();
+
+ return false;
+ }
+ break;
+ case EOpVectorSwizzle:
+ if (visit == InVisit)
+ {
+ out << ".";
+
+ TIntermAggregate *swizzle = node->getRight()->getAsAggregate();
+
+ if (swizzle)
+ {
+ TIntermSequence &sequence = swizzle->getSequence();
+
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermConstantUnion *element = (*sit)->getAsConstantUnion();
+
+ if (element)
+ {
+ int i = element->getUnionArrayPointer()[0].getIConst();
+
+ switch (i)
+ {
+ case 0: out << "x"; break;
+ case 1: out << "y"; break;
+ case 2: out << "z"; break;
+ case 3: out << "w"; break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ return false; // Fully processed
+ }
+ break;
+ case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break;
+ case EOpSub: outputTriplet(visit, "(", " - ", ")"); break;
+ case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break;
+ case EOpEqual:
+ case EOpNotEqual:
+ if (node->getLeft()->isScalar())
+ {
+ if (node->getOp() == EOpEqual)
+ {
+ outputTriplet(visit, "(", " == ", ")");
+ }
+ else
+ {
+ outputTriplet(visit, "(", " != ", ")");
+ }
+ }
+ else if (node->getLeft()->getBasicType() == EbtStruct)
+ {
+ if (node->getOp() == EOpEqual)
+ {
+ out << "(";
+ }
+ else
+ {
+ out << "!(";
+ }
+
+ const TTypeList *fields = node->getLeft()->getType().getStruct();
+
+ for (size_t i = 0; i < fields->size(); i++)
+ {
+ const TType *fieldType = (*fields)[i].type;
+
+ node->getLeft()->traverse(this);
+ out << "." + fieldType->getFieldName() + " == ";
+ node->getRight()->traverse(this);
+ out << "." + fieldType->getFieldName();
+
+ if (i < fields->size() - 1)
+ {
+ out << " && ";
+ }
+ }
+
+ out << ")";
+
+ return false;
+ }
+ else
+ {
+ if (node->getLeft()->isMatrix())
+ {
+ switch (node->getLeft()->getNominalSize())
+ {
+ case 2: mUsesEqualMat2 = true; break;
+ case 3: mUsesEqualMat3 = true; break;
+ case 4: mUsesEqualMat4 = true; break;
+ default: UNREACHABLE();
+ }
+ }
+ else if (node->getLeft()->isVector())
+ {
+ switch (node->getLeft()->getBasicType())
+ {
+ case EbtFloat:
+ switch (node->getLeft()->getNominalSize())
+ {
+ case 2: mUsesEqualVec2 = true; break;
+ case 3: mUsesEqualVec3 = true; break;
+ case 4: mUsesEqualVec4 = true; break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EbtInt:
+ switch (node->getLeft()->getNominalSize())
+ {
+ case 2: mUsesEqualIVec2 = true; break;
+ case 3: mUsesEqualIVec3 = true; break;
+ case 4: mUsesEqualIVec4 = true; break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EbtBool:
+ switch (node->getLeft()->getNominalSize())
+ {
+ case 2: mUsesEqualBVec2 = true; break;
+ case 3: mUsesEqualBVec3 = true; break;
+ case 4: mUsesEqualBVec4 = true; break;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ if (node->getOp() == EOpEqual)
+ {
+ outputTriplet(visit, "equal(", ", ", ")");
+ }
+ else
+ {
+ outputTriplet(visit, "!equal(", ", ", ")");
+ }
+ }
+ break;
+ case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
+ case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpMatrixTimesScalar: outputTriplet(visit, "(", " * ", ")"); break;
+ case EOpVectorTimesMatrix: outputTriplet(visit, "mul(", ", transpose(", "))"); break;
+ case EOpMatrixTimesVector: outputTriplet(visit, "mul(transpose(", "), ", ")"); break;
+ case EOpMatrixTimesMatrix: outputTriplet(visit, "transpose(mul(transpose(", "), transpose(", ")))"); break;
+ case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break;
+ case EOpLogicalXor:
+ mUsesXor = true;
+ outputTriplet(visit, "xor(", ", ", ")");
+ break;
+ case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getOp())
+ {
+ case EOpNegative: outputTriplet(visit, "(-", "", ")"); break;
+ case EOpVectorLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
+ case EOpLogicalNot: outputTriplet(visit, "(!", "", ")"); break;
+ case EOpPostIncrement: outputTriplet(visit, "(", "", "++)"); break;
+ case EOpPostDecrement: outputTriplet(visit, "(", "", "--)"); break;
+ case EOpPreIncrement: outputTriplet(visit, "(++", "", ")"); break;
+ case EOpPreDecrement: outputTriplet(visit, "(--", "", ")"); break;
+ case EOpConvIntToBool:
+ case EOpConvFloatToBool:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "bool(", "", ")"); break;
+ case 2: outputTriplet(visit, "bool2(", "", ")"); break;
+ case 3: outputTriplet(visit, "bool3(", "", ")"); break;
+ case 4: outputTriplet(visit, "bool4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvBoolToFloat:
+ case EOpConvIntToFloat:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "float(", "", ")"); break;
+ case 2: outputTriplet(visit, "float2(", "", ")"); break;
+ case 3: outputTriplet(visit, "float3(", "", ")"); break;
+ case 4: outputTriplet(visit, "float4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpConvFloatToInt:
+ case EOpConvBoolToInt:
+ switch (node->getOperand()->getType().getNominalSize())
+ {
+ case 1: outputTriplet(visit, "int(", "", ")"); break;
+ case 2: outputTriplet(visit, "int2(", "", ")"); break;
+ case 3: outputTriplet(visit, "int3(", "", ")"); break;
+ case 4: outputTriplet(visit, "int4(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+ break;
+ case EOpRadians: outputTriplet(visit, "radians(", "", ")"); break;
+ case EOpDegrees: outputTriplet(visit, "degrees(", "", ")"); break;
+ case EOpSin: outputTriplet(visit, "sin(", "", ")"); break;
+ case EOpCos: outputTriplet(visit, "cos(", "", ")"); break;
+ case EOpTan: outputTriplet(visit, "tan(", "", ")"); break;
+ case EOpAsin: outputTriplet(visit, "asin(", "", ")"); break;
+ case EOpAcos: outputTriplet(visit, "acos(", "", ")"); break;
+ case EOpAtan: outputTriplet(visit, "atan(", "", ")"); break;
+ case EOpExp: outputTriplet(visit, "exp(", "", ")"); break;
+ case EOpLog: outputTriplet(visit, "log(", "", ")"); break;
+ case EOpExp2: outputTriplet(visit, "exp2(", "", ")"); break;
+ case EOpLog2: outputTriplet(visit, "log2(", "", ")"); break;
+ case EOpSqrt: outputTriplet(visit, "sqrt(", "", ")"); break;
+ case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", "", ")"); break;
+ case EOpAbs: outputTriplet(visit, "abs(", "", ")"); break;
+ case EOpSign: outputTriplet(visit, "sign(", "", ")"); break;
+ case EOpFloor: outputTriplet(visit, "floor(", "", ")"); break;
+ case EOpCeil: outputTriplet(visit, "ceil(", "", ")"); break;
+ case EOpFract: outputTriplet(visit, "frac(", "", ")"); break;
+ case EOpLength: outputTriplet(visit, "length(", "", ")"); break;
+ case EOpNormalize: outputTriplet(visit, "normalize(", "", ")"); break;
+ case EOpDFdx: outputTriplet(visit, "ddx(", "", ")"); break;
+ case EOpDFdy: outputTriplet(visit, "(-ddy(", "", "))"); break;
+ case EOpFwidth: outputTriplet(visit, "fwidth(", "", ")"); break;
+ case EOpAny: outputTriplet(visit, "any(", "", ")"); break;
+ case EOpAll: outputTriplet(visit, "all(", "", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+ ShShaderType shaderType = mContext.shaderType;
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ {
+ if (mInsideFunction)
+ {
+ outputLineDirective(node->getLine());
+ out << "{\n";
+
+ mScopeDepth++;
+
+ if (mScopeBracket.size() < mScopeDepth)
+ {
+ mScopeBracket.push_back(0); // New scope level
+ }
+ else
+ {
+ mScopeBracket[mScopeDepth - 1]++; // New scope at existing level
+ }
+ }
+
+ for (TIntermSequence::iterator sit = node->getSequence().begin(); sit != node->getSequence().end(); sit++)
+ {
+ outputLineDirective((*sit)->getLine());
+
+ if (isSingleStatement(*sit))
+ {
+ mUnfoldSelect->traverse(*sit);
+ }
+
+ (*sit)->traverse(this);
+
+ out << ";\n";
+ }
+
+ if (mInsideFunction)
+ {
+ outputLineDirective(node->getEndLine());
+ out << "}\n";
+
+ mScopeDepth--;
+ }
+
+ return false;
+ }
+ case EOpDeclaration:
+ if (visit == PreVisit)
+ {
+ TIntermSequence &sequence = node->getSequence();
+ TIntermTyped *variable = sequence[0]->getAsTyped();
+ bool visit = true;
+
+ if (variable && (variable->getQualifier() == EvqTemporary || variable->getQualifier() == EvqGlobal))
+ {
+ if (variable->getType().getStruct())
+ {
+ addConstructor(variable->getType(), scopedStruct(variable->getType().getTypeName()), NULL);
+ }
+
+ if (!variable->getAsSymbolNode() || variable->getAsSymbolNode()->getSymbol() != "") // Variable declaration
+ {
+ if (!mInsideFunction)
+ {
+ out << "static ";
+ }
+
+ out << typeString(variable->getType()) + " ";
+
+ for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++)
+ {
+ TIntermSymbol *symbol = (*sit)->getAsSymbolNode();
+
+ if (symbol)
+ {
+ symbol->traverse(this);
+ out << arrayString(symbol->getType());
+ out << " = " + initializer(variable->getType());
+ }
+ else
+ {
+ (*sit)->traverse(this);
+ }
+
+ if (visit && this->inVisit)
+ {
+ if (*sit != sequence.back())
+ {
+ visit = this->visitAggregate(InVisit, node);
+ }
+ }
+ }
+
+ if (visit && this->postVisit)
+ {
+ this->visitAggregate(PostVisit, node);
+ }
+ }
+ else if (variable->getAsSymbolNode() && variable->getAsSymbolNode()->getSymbol() == "") // Type (struct) declaration
+ {
+ // Already added to constructor map
+ }
+ else UNREACHABLE();
+ }
+
+ return false;
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ break;
+ case EOpPrototype:
+ if (visit == PreVisit)
+ {
+ out << typeString(node->getType()) << " " << decorate(node->getName()) << "(";
+
+ TIntermSequence &arguments = node->getSequence();
+
+ for (unsigned int i = 0; i < arguments.size(); i++)
+ {
+ TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ out << argumentString(symbol);
+
+ if (i < arguments.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ out << ");\n";
+
+ return false;
+ }
+ break;
+ case EOpComma: outputTriplet(visit, "", ", ", ""); break;
+ case EOpFunction:
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ if (visit == PreVisit)
+ {
+ out << typeString(node->getType()) << " ";
+
+ if (name == "main")
+ {
+ out << "gl_main(";
+ }
+ else
+ {
+ out << decorate(name) << "(";
+ }
+
+ TIntermSequence &sequence = node->getSequence();
+ TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence();
+
+ for (unsigned int i = 0; i < arguments.size(); i++)
+ {
+ TIntermSymbol *symbol = arguments[i]->getAsSymbolNode();
+
+ if (symbol)
+ {
+ out << argumentString(symbol);
+
+ if (i < arguments.size() - 1)
+ {
+ out << ", ";
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ sequence.erase(sequence.begin());
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+
+ mInsideFunction = true;
+ }
+ else if (visit == PostVisit)
+ {
+ outputLineDirective(node->getEndLine());
+ out << "}\n";
+
+ mInsideFunction = false;
+ }
+ }
+ break;
+ case EOpFunctionCall:
+ {
+ if (visit == PreVisit)
+ {
+ TString name = TFunction::unmangleName(node->getName());
+
+ if (node->isUserDefined())
+ {
+ out << decorate(name) << "(";
+ }
+ else
+ {
+ if (name == "texture2D")
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2D = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2D_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2D(";
+ }
+ else if (name == "texture2DProj")
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTexture2DProj = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DProj_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DProj(";
+ }
+ else if (name == "textureCube")
+ {
+ if (node->getSequence().size() == 2)
+ {
+ mUsesTextureCube = true;
+ }
+ else if (node->getSequence().size() == 3)
+ {
+ mUsesTextureCube_bias = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_textureCube(";
+ }
+ else if (name == "texture2DLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DLod(";
+ }
+ else if (name == "texture2DProjLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTexture2DProjLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_texture2DProjLod(";
+ }
+ else if (name == "textureCubeLod")
+ {
+ if (node->getSequence().size() == 3)
+ {
+ mUsesTextureCubeLod = true;
+ }
+ else UNREACHABLE();
+
+ out << "gl_textureCubeLod(";
+ }
+ else UNREACHABLE();
+ }
+ }
+ else if (visit == InVisit)
+ {
+ out << ", ";
+ }
+ else
+ {
+ out << ")";
+ }
+ }
+ break;
+ case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break;
+ case EOpConstructFloat:
+ addConstructor(node->getType(), "vec1", &node->getSequence());
+ outputTriplet(visit, "vec1(", "", ")");
+ break;
+ case EOpConstructVec2:
+ addConstructor(node->getType(), "vec2", &node->getSequence());
+ outputTriplet(visit, "vec2(", ", ", ")");
+ break;
+ case EOpConstructVec3:
+ addConstructor(node->getType(), "vec3", &node->getSequence());
+ outputTriplet(visit, "vec3(", ", ", ")");
+ break;
+ case EOpConstructVec4:
+ addConstructor(node->getType(), "vec4", &node->getSequence());
+ outputTriplet(visit, "vec4(", ", ", ")");
+ break;
+ case EOpConstructBool:
+ addConstructor(node->getType(), "bvec1", &node->getSequence());
+ outputTriplet(visit, "bvec1(", "", ")");
+ break;
+ case EOpConstructBVec2:
+ addConstructor(node->getType(), "bvec2", &node->getSequence());
+ outputTriplet(visit, "bvec2(", ", ", ")");
+ break;
+ case EOpConstructBVec3:
+ addConstructor(node->getType(), "bvec3", &node->getSequence());
+ outputTriplet(visit, "bvec3(", ", ", ")");
+ break;
+ case EOpConstructBVec4:
+ addConstructor(node->getType(), "bvec4", &node->getSequence());
+ outputTriplet(visit, "bvec4(", ", ", ")");
+ break;
+ case EOpConstructInt:
+ addConstructor(node->getType(), "ivec1", &node->getSequence());
+ outputTriplet(visit, "ivec1(", "", ")");
+ break;
+ case EOpConstructIVec2:
+ addConstructor(node->getType(), "ivec2", &node->getSequence());
+ outputTriplet(visit, "ivec2(", ", ", ")");
+ break;
+ case EOpConstructIVec3:
+ addConstructor(node->getType(), "ivec3", &node->getSequence());
+ outputTriplet(visit, "ivec3(", ", ", ")");
+ break;
+ case EOpConstructIVec4:
+ addConstructor(node->getType(), "ivec4", &node->getSequence());
+ outputTriplet(visit, "ivec4(", ", ", ")");
+ break;
+ case EOpConstructMat2:
+ addConstructor(node->getType(), "mat2", &node->getSequence());
+ outputTriplet(visit, "mat2(", ", ", ")");
+ break;
+ case EOpConstructMat3:
+ addConstructor(node->getType(), "mat3", &node->getSequence());
+ outputTriplet(visit, "mat3(", ", ", ")");
+ break;
+ case EOpConstructMat4:
+ addConstructor(node->getType(), "mat4", &node->getSequence());
+ outputTriplet(visit, "mat4(", ", ", ")");
+ break;
+ case EOpConstructStruct:
+ addConstructor(node->getType(), scopedStruct(node->getType().getTypeName()), &node->getSequence());
+ outputTriplet(visit, structLookup(node->getType().getTypeName()) + "_ctor(", ", ", ")");
+ break;
+ case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break;
+ case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break;
+ case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break;
+ case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break;
+ case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break;
+ case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break;
+ case EOpMod:
+ {
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
+ {
+ case 1: mUsesMod1 = true; break;
+ case 2: mUsesMod2 = true; break;
+ case 3: mUsesMod3 = true; break;
+ case 4: mUsesMod4 = true; break;
+ default: UNREACHABLE();
+ }
+
+ outputTriplet(visit, "mod(", ", ", ")");
+ }
+ break;
+ case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break;
+ case EOpAtan:
+ ASSERT(node->getSequence().size() == 2); // atan(x) is a unary operator
+ mUsesAtan2 = true;
+ outputTriplet(visit, "atanyx(", ", ", ")");
+ break;
+ case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break;
+ case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break;
+ case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break;
+ case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break;
+ case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break;
+ case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break;
+ case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break;
+ case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break;
+ case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break;
+ case EOpFaceForward:
+ {
+ switch (node->getSequence()[0]->getAsTyped()->getNominalSize()) // Number of components in the first argument
+ {
+ case 1: mUsesFaceforward1 = true; break;
+ case 2: mUsesFaceforward2 = true; break;
+ case 3: mUsesFaceforward3 = true; break;
+ case 4: mUsesFaceforward4 = true; break;
+ default: UNREACHABLE();
+ }
+
+ outputTriplet(visit, "faceforward(", ", ", ")");
+ }
+ break;
+ case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break;
+ case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break;
+ case EOpMul: outputTriplet(visit, "(", " * ", ")"); break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (node->usesTernaryOperator())
+ {
+ out << "t" << mUnfoldSelect->getTemporaryIndex();
+ }
+ else // if/else statement
+ {
+ mUnfoldSelect->traverse(node->getCondition());
+
+ out << "if(";
+
+ node->getCondition()->traverse(this);
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+
+ if (node->getTrueBlock())
+ {
+ node->getTrueBlock()->traverse(this);
+ }
+
+ outputLineDirective(node->getLine());
+ out << ";}\n";
+
+ if (node->getFalseBlock())
+ {
+ out << "else\n";
+
+ outputLineDirective(node->getFalseBlock()->getLine());
+ out << "{\n";
+
+ outputLineDirective(node->getFalseBlock()->getLine());
+ node->getFalseBlock()->traverse(this);
+
+ outputLineDirective(node->getFalseBlock()->getLine());
+ out << ";}\n";
+ }
+ }
+
+ return false;
+}
+
+void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node)
+{
+ writeConstantUnion(node->getType(), node->getUnionArrayPointer());
+}
+
+bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node)
+{
+ if (handleExcessiveLoop(node))
+ {
+ return false;
+ }
+
+ TInfoSinkBase &out = mBody;
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ out << "do\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+ }
+ else
+ {
+ if (node->getInit())
+ {
+ mUnfoldSelect->traverse(node->getInit());
+ }
+
+ if (node->getCondition())
+ {
+ mUnfoldSelect->traverse(node->getCondition());
+ }
+
+ if (node->getExpression())
+ {
+ mUnfoldSelect->traverse(node->getExpression());
+ }
+
+ out << "for(";
+
+ if (node->getInit())
+ {
+ node->getInit()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getCondition())
+ {
+ node->getCondition()->traverse(this);
+ }
+
+ out << "; ";
+
+ if (node->getExpression())
+ {
+ node->getExpression()->traverse(this);
+ }
+
+ out << ")\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+ }
+
+ if (node->getBody())
+ {
+ node->getBody()->traverse(this);
+ }
+
+ outputLineDirective(node->getLine());
+ out << "}\n";
+
+ if (node->getType() == ELoopDoWhile)
+ {
+ outputLineDirective(node->getCondition()->getLine());
+ out << "while(\n";
+
+ node->getCondition()->traverse(this);
+
+ out << ")";
+ }
+
+ out << ";\n";
+
+ return false;
+}
+
+bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ switch (node->getFlowOp())
+ {
+ case EOpKill: outputTriplet(visit, "discard;\n", "", ""); break;
+ case EOpBreak: outputTriplet(visit, "break;\n", "", ""); break;
+ case EOpContinue: outputTriplet(visit, "continue;\n", "", ""); break;
+ case EOpReturn:
+ if (visit == PreVisit)
+ {
+ if (node->getExpression())
+ {
+ out << "return ";
+ }
+ else
+ {
+ out << "return;\n";
+ }
+ }
+ else if (visit == PostVisit)
+ {
+ if (node->getExpression())
+ {
+ out << ";\n";
+ }
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool OutputHLSL::isSingleStatement(TIntermNode *node)
+{
+ TIntermAggregate *aggregate = node->getAsAggregate();
+
+ if (aggregate)
+ {
+ if (aggregate->getOp() == EOpSequence)
+ {
+ return false;
+ }
+ else
+ {
+ for (TIntermSequence::iterator sit = aggregate->getSequence().begin(); sit != aggregate->getSequence().end(); sit++)
+ {
+ if (!isSingleStatement(*sit))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ return true;
+}
+
+// Handle loops with more than 255 iterations (unsupported by D3D9) by splitting them
+bool OutputHLSL::handleExcessiveLoop(TIntermLoop *node)
+{
+ TInfoSinkBase &out = mBody;
+
+ // Parse loops of the form:
+ // for(int index = initial; index [comparator] limit; index += increment)
+ TIntermSymbol *index = NULL;
+ TOperator comparator = EOpNull;
+ int initial = 0;
+ int limit = 0;
+ int increment = 0;
+
+ // Parse index name and intial value
+ if (node->getInit())
+ {
+ TIntermAggregate *init = node->getInit()->getAsAggregate();
+
+ if (init)
+ {
+ TIntermSequence &sequence = init->getSequence();
+ TIntermTyped *variable = sequence[0]->getAsTyped();
+
+ if (variable && variable->getQualifier() == EvqTemporary)
+ {
+ TIntermBinary *assign = variable->getAsBinaryNode();
+
+ if (assign->getOp() == EOpInitialize)
+ {
+ TIntermSymbol *symbol = assign->getLeft()->getAsSymbolNode();
+ TIntermConstantUnion *constant = assign->getRight()->getAsConstantUnion();
+
+ if (symbol && constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ index = symbol;
+ initial = constant->getUnionArrayPointer()[0].getIConst();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Parse comparator and limit value
+ if (index != NULL && node->getCondition())
+ {
+ TIntermBinary *test = node->getCondition()->getAsBinaryNode();
+
+ if (test && test->getLeft()->getAsSymbolNode()->getId() == index->getId())
+ {
+ TIntermConstantUnion *constant = test->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ comparator = test->getOp();
+ limit = constant->getUnionArrayPointer()[0].getIConst();
+ }
+ }
+ }
+ }
+
+ // Parse increment
+ if (index != NULL && comparator != EOpNull && node->getExpression())
+ {
+ TIntermBinary *binaryTerminal = node->getExpression()->getAsBinaryNode();
+ TIntermUnary *unaryTerminal = node->getExpression()->getAsUnaryNode();
+
+ if (binaryTerminal)
+ {
+ TOperator op = binaryTerminal->getOp();
+ TIntermConstantUnion *constant = binaryTerminal->getRight()->getAsConstantUnion();
+
+ if (constant)
+ {
+ if (constant->getBasicType() == EbtInt && constant->getNominalSize() == 1)
+ {
+ int value = constant->getUnionArrayPointer()[0].getIConst();
+
+ switch (op)
+ {
+ case EOpAddAssign: increment = value; break;
+ case EOpSubAssign: increment = -value; break;
+ default: UNIMPLEMENTED();
+ }
+ }
+ }
+ }
+ else if (unaryTerminal)
+ {
+ TOperator op = unaryTerminal->getOp();
+
+ switch (op)
+ {
+ case EOpPostIncrement: increment = 1; break;
+ case EOpPostDecrement: increment = -1; break;
+ case EOpPreIncrement: increment = 1; break;
+ case EOpPreDecrement: increment = -1; break;
+ default: UNIMPLEMENTED();
+ }
+ }
+ }
+
+ if (index != NULL && comparator != EOpNull && increment != 0)
+ {
+ if (comparator == EOpLessThanEqual)
+ {
+ comparator = EOpLessThan;
+ limit += 1;
+ }
+
+ if (comparator == EOpLessThan)
+ {
+ int iterations = (limit - initial) / increment;
+
+ if (iterations <= 255)
+ {
+ return false; // Not an excessive loop
+ }
+
+ while (iterations > 0)
+ {
+ int remainder = (limit - initial) % increment;
+ int clampedLimit = initial + increment * std::min(255, iterations);
+
+ // for(int index = initial; index < clampedLimit; index += increment)
+
+ out << "for(int ";
+ index->traverse(this);
+ out << " = ";
+ out << initial;
+
+ out << "; ";
+ index->traverse(this);
+ out << " < ";
+ out << clampedLimit;
+
+ out << "; ";
+ index->traverse(this);
+ out << " += ";
+ out << increment;
+ out << ")\n";
+
+ outputLineDirective(node->getLine());
+ out << "{\n";
+
+ if (node->getBody())
+ {
+ node->getBody()->traverse(this);
+ }
+
+ outputLineDirective(node->getLine());
+ out << "}\n";
+
+ initial += 255 * increment;
+ iterations -= 255;
+ }
+
+ return true;
+ }
+ else UNIMPLEMENTED();
+ }
+
+ return false; // Not handled as an excessive loop
+}
+
+void OutputHLSL::outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (visit == PreVisit)
+ {
+ out << preString;
+ }
+ else if (visit == InVisit)
+ {
+ out << inString;
+ }
+ else if (visit == PostVisit)
+ {
+ out << postString;
+ }
+}
+
+void OutputHLSL::outputLineDirective(int line)
+{
+ if ((mContext.compileOptions & SH_LINE_DIRECTIVES) && (line > 0))
+ {
+ mBody << "\n";
+ mBody << "#line " << line;
+
+ if (mContext.sourcePath)
+ {
+ mBody << " \"" << mContext.sourcePath << "\"";
+ }
+
+ mBody << "\n";
+ }
+}
+
+TString OutputHLSL::argumentString(const TIntermSymbol *symbol)
+{
+ TQualifier qualifier = symbol->getQualifier();
+ const TType &type = symbol->getType();
+ TString name = symbol->getSymbol();
+
+ if (name.empty()) // HLSL demands named arguments, also for prototypes
+ {
+ name = "x" + str(mUniqueIndex++);
+ }
+ else
+ {
+ name = decorate(name);
+ }
+
+ return qualifierString(qualifier) + " " + typeString(type) + " " + name + arrayString(type);
+}
+
+TString OutputHLSL::qualifierString(TQualifier qualifier)
+{
+ switch(qualifier)
+ {
+ case EvqIn: return "in";
+ case EvqOut: return "out";
+ case EvqInOut: return "inout";
+ case EvqConstReadOnly: return "const";
+ default: UNREACHABLE();
+ }
+
+ return "";
+}
+
+TString OutputHLSL::typeString(const TType &type)
+{
+ if (type.getBasicType() == EbtStruct)
+ {
+ if (type.getTypeName() != "")
+ {
+ return structLookup(type.getTypeName());
+ }
+ else // Nameless structure, define in place
+ {
+ const TTypeList &fields = *type.getStruct();
+
+ TString string = "struct\n"
+ "{\n";
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ const TType &field = *fields[i].type;
+
+ string += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
+ }
+
+ string += "} ";
+
+ return string;
+ }
+ }
+ else if (type.isMatrix())
+ {
+ switch (type.getNominalSize())
+ {
+ case 2: return "float2x2";
+ case 3: return "float3x3";
+ case 4: return "float4x4";
+ }
+ }
+ else
+ {
+ switch (type.getBasicType())
+ {
+ case EbtFloat:
+ switch (type.getNominalSize())
+ {
+ case 1: return "float";
+ case 2: return "float2";
+ case 3: return "float3";
+ case 4: return "float4";
+ }
+ case EbtInt:
+ switch (type.getNominalSize())
+ {
+ case 1: return "int";
+ case 2: return "int2";
+ case 3: return "int3";
+ case 4: return "int4";
+ }
+ case EbtBool:
+ switch (type.getNominalSize())
+ {
+ case 1: return "bool";
+ case 2: return "bool2";
+ case 3: return "bool3";
+ case 4: return "bool4";
+ }
+ case EbtVoid:
+ return "void";
+ case EbtSampler2D:
+ return "sampler2D";
+ case EbtSamplerCube:
+ return "samplerCUBE";
+ }
+ }
+
+ UNIMPLEMENTED(); // FIXME
+ return "<unknown type>";
+}
+
+TString OutputHLSL::arrayString(const TType &type)
+{
+ if (!type.isArray())
+ {
+ return "";
+ }
+
+ return "[" + str(type.getArraySize()) + "]";
+}
+
+TString OutputHLSL::initializer(const TType &type)
+{
+ TString string;
+
+ for (int component = 0; component < type.getObjectSize(); component++)
+ {
+ string += "0";
+
+ if (component < type.getObjectSize() - 1)
+ {
+ string += ", ";
+ }
+ }
+
+ return "{" + string + "}";
+}
+
+void OutputHLSL::addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters)
+{
+ if (name == "")
+ {
+ return; // Nameless structures don't have constructors
+ }
+
+ TType ctorType = type;
+ ctorType.clearArrayness();
+ ctorType.setPrecision(EbpHigh);
+ ctorType.setQualifier(EvqTemporary);
+
+ TString ctorName = type.getStruct() ? decorate(name) : name;
+
+ typedef std::vector<TType> ParameterArray;
+ ParameterArray ctorParameters;
+
+ if (parameters)
+ {
+ for (TIntermSequence::const_iterator parameter = parameters->begin(); parameter != parameters->end(); parameter++)
+ {
+ ctorParameters.push_back((*parameter)->getAsTyped()->getType());
+ }
+ }
+ else if (type.getStruct())
+ {
+ mStructNames.insert(decorate(name));
+
+ TString structure;
+ structure += "struct " + decorate(name) + "\n"
+ "{\n";
+
+ const TTypeList &fields = *type.getStruct();
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ const TType &field = *fields[i].type;
+
+ structure += " " + typeString(field) + " " + field.getFieldName() + arrayString(field) + ";\n";
+ }
+
+ structure += "};\n";
+
+ if (std::find(mStructDeclarations.begin(), mStructDeclarations.end(), structure) == mStructDeclarations.end())
+ {
+ mStructDeclarations.push_back(structure);
+ }
+
+ for (unsigned int i = 0; i < fields.size(); i++)
+ {
+ ctorParameters.push_back(*fields[i].type);
+ }
+ }
+ else UNREACHABLE();
+
+ TString constructor;
+
+ if (ctorType.getStruct())
+ {
+ constructor += ctorName + " " + ctorName + "_ctor(";
+ }
+ else // Built-in type
+ {
+ constructor += typeString(ctorType) + " " + ctorName + "(";
+ }
+
+ for (unsigned int parameter = 0; parameter < ctorParameters.size(); parameter++)
+ {
+ const TType &type = ctorParameters[parameter];
+
+ constructor += typeString(type) + " x" + str(parameter) + arrayString(type);
+
+ if (parameter < ctorParameters.size() - 1)
+ {
+ constructor += ", ";
+ }
+ }
+
+ constructor += ")\n"
+ "{\n";
+
+ if (ctorType.getStruct())
+ {
+ constructor += " " + ctorName + " structure = {";
+ }
+ else
+ {
+ constructor += " return " + typeString(ctorType) + "(";
+ }
+
+ if (ctorType.isMatrix() && ctorParameters.size() == 1)
+ {
+ int dim = ctorType.getNominalSize();
+ const TType &parameter = ctorParameters[0];
+
+ if (parameter.isScalar())
+ {
+ for (int row = 0; row < dim; row++)
+ {
+ for (int col = 0; col < dim; col++)
+ {
+ constructor += TString((row == col) ? "x0" : "0.0");
+
+ if (row < dim - 1 || col < dim - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else if (parameter.isMatrix())
+ {
+ for (int row = 0; row < dim; row++)
+ {
+ for (int col = 0; col < dim; col++)
+ {
+ if (row < parameter.getNominalSize() && col < parameter.getNominalSize())
+ {
+ constructor += TString("x0") + "[" + str(row) + "]" + "[" + str(col) + "]";
+ }
+ else
+ {
+ constructor += TString((row == col) ? "1.0" : "0.0");
+ }
+
+ if (row < dim - 1 || col < dim - 1)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+ }
+ else UNREACHABLE();
+ }
+ else
+ {
+ int remainingComponents = ctorType.getObjectSize();
+ int parameterIndex = 0;
+
+ while (remainingComponents > 0)
+ {
+ const TType &parameter = ctorParameters[parameterIndex];
+ bool moreParameters = parameterIndex < (int)ctorParameters.size() - 1;
+
+ constructor += "x" + str(parameterIndex);
+
+ if (parameter.isScalar())
+ {
+ remainingComponents -= parameter.getObjectSize();
+ }
+ else if (parameter.isVector())
+ {
+ if (remainingComponents == parameter.getObjectSize() || moreParameters)
+ {
+ remainingComponents -= parameter.getObjectSize();
+ }
+ else if (remainingComponents < parameter.getNominalSize())
+ {
+ switch (remainingComponents)
+ {
+ case 1: constructor += ".x"; break;
+ case 2: constructor += ".xy"; break;
+ case 3: constructor += ".xyz"; break;
+ case 4: constructor += ".xyzw"; break;
+ default: UNREACHABLE();
+ }
+
+ remainingComponents = 0;
+ }
+ else UNREACHABLE();
+ }
+ else if (parameter.isMatrix() || parameter.getStruct())
+ {
+ ASSERT(remainingComponents == parameter.getObjectSize() || moreParameters);
+
+ remainingComponents -= parameter.getObjectSize();
+ }
+ else UNREACHABLE();
+
+ if (moreParameters)
+ {
+ parameterIndex++;
+ }
+
+ if (remainingComponents)
+ {
+ constructor += ", ";
+ }
+ }
+ }
+
+ if (ctorType.getStruct())
+ {
+ constructor += "};\n"
+ " return structure;\n"
+ "}\n";
+ }
+ else
+ {
+ constructor += ");\n"
+ "}\n";
+ }
+
+ mConstructors.insert(constructor);
+}
+
+const ConstantUnion *OutputHLSL::writeConstantUnion(const TType &type, const ConstantUnion *constUnion)
+{
+ TInfoSinkBase &out = mBody;
+
+ if (type.getBasicType() == EbtStruct)
+ {
+ out << structLookup(type.getTypeName()) + "_ctor(";
+
+ const TTypeList *structure = type.getStruct();
+
+ for (size_t i = 0; i < structure->size(); i++)
+ {
+ const TType *fieldType = (*structure)[i].type;
+
+ constUnion = writeConstantUnion(*fieldType, constUnion);
+
+ if (i != structure->size() - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ out << ")";
+ }
+ else
+ {
+ int size = type.getObjectSize();
+ bool writeType = size > 1;
+
+ if (writeType)
+ {
+ out << typeString(type) << "(";
+ }
+
+ for (int i = 0; i < size; i++, constUnion++)
+ {
+ switch (constUnion->getType())
+ {
+ case EbtFloat: out << constUnion->getFConst(); break;
+ case EbtInt: out << constUnion->getIConst(); break;
+ case EbtBool: out << constUnion->getBConst(); break;
+ default: UNREACHABLE();
+ }
+
+ if (i != size - 1)
+ {
+ out << ", ";
+ }
+ }
+
+ if (writeType)
+ {
+ out << ")";
+ }
+ }
+
+ return constUnion;
+}
+
+TString OutputHLSL::scopeString(unsigned int depthLimit)
+{
+ TString string;
+
+ for (unsigned int i = 0; i < mScopeBracket.size() && i < depthLimit; i++)
+ {
+ string += "_" + str(i);
+ }
+
+ return string;
+}
+
+TString OutputHLSL::scopedStruct(const TString &typeName)
+{
+ if (typeName == "")
+ {
+ return typeName;
+ }
+
+ return typeName + scopeString(mScopeDepth);
+}
+
+TString OutputHLSL::structLookup(const TString &typeName)
+{
+ for (int depth = mScopeDepth; depth >= 0; depth--)
+ {
+ TString scopedName = decorate(typeName + scopeString(depth));
+
+ for (StructNames::iterator structName = mStructNames.begin(); structName != mStructNames.end(); structName++)
+ {
+ if (*structName == scopedName)
+ {
+ return scopedName;
+ }
+ }
+ }
+
+ UNREACHABLE(); // Should have found a matching constructor
+
+ return typeName;
+}
+
+TString OutputHLSL::decorate(const TString &string)
+{
+ if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
+ {
+ return "_" + string;
+ }
+ else
+ {
+ return string;
+ }
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.h
new file mode 100644
index 000000000..805561afb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/OutputHLSL.h
@@ -0,0 +1,131 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_OUTPUTHLSL_H_
+#define COMPILER_OUTPUTHLSL_H_
+
+#include <list>
+#include <set>
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+class UnfoldSelect;
+
+class OutputHLSL : public TIntermTraverser
+{
+ public:
+ explicit OutputHLSL(TParseContext &context);
+ ~OutputHLSL();
+
+ void output();
+
+ TInfoSinkBase &getBodyStream();
+
+ TString typeString(const TType &type);
+ static TString qualifierString(TQualifier qualifier);
+ static TString arrayString(const TType &type);
+ static TString initializer(const TType &type);
+ static TString decorate(const TString &string); // Prepend an underscore to avoid naming clashes
+
+ protected:
+ void header();
+
+ // Visit AST nodes and output their code to the body stream
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+
+ bool isSingleStatement(TIntermNode *node);
+ bool handleExcessiveLoop(TIntermLoop *node);
+ void outputTriplet(Visit visit, const TString &preString, const TString &inString, const TString &postString);
+ void outputLineDirective(int line);
+ TString argumentString(const TIntermSymbol *symbol);
+ int vectorSize(const TType &type) const;
+
+ void addConstructor(const TType &type, const TString &name, const TIntermSequence *parameters);
+ const ConstantUnion *writeConstantUnion(const TType &type, const ConstantUnion *constUnion);
+
+ TString scopeString(unsigned int depthLimit);
+ TString scopedStruct(const TString &typeName);
+ TString structLookup(const TString &typeName);
+
+ TParseContext &mContext;
+ UnfoldSelect *mUnfoldSelect;
+ bool mInsideFunction;
+
+ // Output streams
+ TInfoSinkBase mHeader;
+ TInfoSinkBase mBody;
+ TInfoSinkBase mFooter;
+
+ std::set<std::string> mReferencedUniforms;
+ std::set<std::string> mReferencedAttributes;
+ std::set<std::string> mReferencedVaryings;
+
+ // Parameters determining what goes in the header output
+ bool mUsesTexture2D;
+ bool mUsesTexture2D_bias;
+ bool mUsesTexture2DLod;
+ bool mUsesTexture2DProj;
+ bool mUsesTexture2DProj_bias;
+ bool mUsesTexture2DProjLod;
+ bool mUsesTextureCube;
+ bool mUsesTextureCube_bias;
+ bool mUsesTextureCubeLod;
+ bool mUsesDepthRange;
+ bool mUsesFragCoord;
+ bool mUsesPointCoord;
+ bool mUsesFrontFacing;
+ bool mUsesPointSize;
+ bool mUsesXor;
+ bool mUsesMod1;
+ bool mUsesMod2;
+ bool mUsesMod3;
+ bool mUsesMod4;
+ bool mUsesFaceforward1;
+ bool mUsesFaceforward2;
+ bool mUsesFaceforward3;
+ bool mUsesFaceforward4;
+ bool mUsesEqualMat2;
+ bool mUsesEqualMat3;
+ bool mUsesEqualMat4;
+ bool mUsesEqualVec2;
+ bool mUsesEqualVec3;
+ bool mUsesEqualVec4;
+ bool mUsesEqualIVec2;
+ bool mUsesEqualIVec3;
+ bool mUsesEqualIVec4;
+ bool mUsesEqualBVec2;
+ bool mUsesEqualBVec3;
+ bool mUsesEqualBVec4;
+ bool mUsesAtan2;
+
+ typedef std::set<TString> Constructors;
+ Constructors mConstructors;
+
+ typedef std::set<TString> StructNames;
+ StructNames mStructNames;
+
+ typedef std::list<TString> StructDeclarations;
+ StructDeclarations mStructDeclarations;
+
+ typedef std::vector<int> ScopeBracket;
+ ScopeBracket mScopeBracket;
+ unsigned int mScopeDepth;
+
+ int mUniqueIndex; // For creating unique names
+};
+}
+
+#endif // COMPILER_OUTPUTHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ParseHelper.cpp b/Source/ThirdParty/ANGLE/src/compiler/ParseHelper.cpp
new file mode 100644
index 000000000..3f0836d75
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ParseHelper.cpp
@@ -0,0 +1,1533 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/ParseHelper.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "compiler/glslang.h"
+#include "compiler/osinclude.h"
+#include "compiler/InitializeParseContext.h"
+
+extern "C" {
+extern int InitPreprocessor();
+extern int FinalizePreprocessor();
+extern void PredefineIntMacro(const char *name, int value);
+}
+
+static void ReportInfo(TInfoSinkBase& sink,
+ TPrefixType type, TSourceLoc loc,
+ const char* reason, const char* token,
+ const char* extraInfo)
+{
+ /* VC++ format: file(linenum) : error #: 'token' : extrainfo */
+ sink.prefix(type);
+ sink.location(loc);
+ sink << "'" << token << "' : " << reason << " " << extraInfo << "\n";
+}
+
+static void DefineExtensionMacros(const TExtensionBehavior& extBehavior)
+{
+ for (TExtensionBehavior::const_iterator iter = extBehavior.begin();
+ iter != extBehavior.end(); ++iter) {
+ PredefineIntMacro(iter->first.c_str(), 1);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Sub- vector and matrix fields
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a vector.
+//
+bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, int line)
+{
+ fields.num = (int) compString.size();
+ if (fields.num > 4) {
+ error(line, "illegal vector field selection", compString.c_str(), "");
+ return false;
+ }
+
+ enum {
+ exyzw,
+ ergba,
+ estpq,
+ } fieldSet[4];
+
+ for (int i = 0; i < fields.num; ++i) {
+ switch (compString[i]) {
+ case 'x':
+ fields.offsets[i] = 0;
+ fieldSet[i] = exyzw;
+ break;
+ case 'r':
+ fields.offsets[i] = 0;
+ fieldSet[i] = ergba;
+ break;
+ case 's':
+ fields.offsets[i] = 0;
+ fieldSet[i] = estpq;
+ break;
+ case 'y':
+ fields.offsets[i] = 1;
+ fieldSet[i] = exyzw;
+ break;
+ case 'g':
+ fields.offsets[i] = 1;
+ fieldSet[i] = ergba;
+ break;
+ case 't':
+ fields.offsets[i] = 1;
+ fieldSet[i] = estpq;
+ break;
+ case 'z':
+ fields.offsets[i] = 2;
+ fieldSet[i] = exyzw;
+ break;
+ case 'b':
+ fields.offsets[i] = 2;
+ fieldSet[i] = ergba;
+ break;
+ case 'p':
+ fields.offsets[i] = 2;
+ fieldSet[i] = estpq;
+ break;
+
+ case 'w':
+ fields.offsets[i] = 3;
+ fieldSet[i] = exyzw;
+ break;
+ case 'a':
+ fields.offsets[i] = 3;
+ fieldSet[i] = ergba;
+ break;
+ case 'q':
+ fields.offsets[i] = 3;
+ fieldSet[i] = estpq;
+ break;
+ default:
+ error(line, "illegal vector field selection", compString.c_str(), "");
+ return false;
+ }
+ }
+
+ for (int i = 0; i < fields.num; ++i) {
+ if (fields.offsets[i] >= vecSize) {
+ error(line, "vector field selection out of range", compString.c_str(), "");
+ return false;
+ }
+
+ if (i > 0) {
+ if (fieldSet[i] != fieldSet[i-1]) {
+ error(line, "illegal - vector component fields not from the same set", compString.c_str(), "");
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+//
+// Look at a '.' field selector string and change it into offsets
+// for a matrix.
+//
+bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, int line)
+{
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = -1;
+ fields.col = -1;
+
+ if (compString.size() != 2) {
+ error(line, "illegal length of matrix field selection", compString.c_str(), "");
+ return false;
+ }
+
+ if (compString[0] == '_') {
+ if (compString[1] < '0' || compString[1] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str(), "");
+ return false;
+ }
+ fields.wholeCol = true;
+ fields.col = compString[1] - '0';
+ } else if (compString[1] == '_') {
+ if (compString[0] < '0' || compString[0] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str(), "");
+ return false;
+ }
+ fields.wholeRow = true;
+ fields.row = compString[0] - '0';
+ } else {
+ if (compString[0] < '0' || compString[0] > '3' ||
+ compString[1] < '0' || compString[1] > '3') {
+ error(line, "illegal matrix field selection", compString.c_str(), "");
+ return false;
+ }
+ fields.row = compString[0] - '0';
+ fields.col = compString[1] - '0';
+ }
+
+ if (fields.row >= matSize || fields.col >= matSize) {
+ error(line, "matrix field selection out of range", compString.c_str(), "");
+ return false;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////
+//
+// Errors
+//
+////////////////////////////////////////////////////////////////////////
+
+//
+// Track whether errors have occurred.
+//
+void TParseContext::recover()
+{
+ recoveredFromError = true;
+}
+
+//
+// Used by flex/bison to output all syntax and parsing errors.
+//
+void TParseContext::error(TSourceLoc loc,
+ const char* reason, const char* token,
+ const char* extraInfoFormat, ...)
+{
+ char extraInfo[512];
+ va_list marker;
+ va_start(marker, extraInfoFormat);
+ vsnprintf(extraInfo, sizeof(extraInfo), extraInfoFormat, marker);
+
+ ReportInfo(infoSink.info, EPrefixError, loc, reason, token, extraInfo);
+
+ va_end(marker);
+ ++numErrors;
+}
+
+void TParseContext::warning(TSourceLoc loc,
+ const char* reason, const char* token,
+ const char* extraInfoFormat, ...) {
+ char extraInfo[512];
+ va_list marker;
+ va_start(marker, extraInfoFormat);
+ vsnprintf(extraInfo, sizeof(extraInfo), extraInfoFormat, marker);
+
+ ReportInfo(infoSink.info, EPrefixWarning, loc, reason, token, extraInfo);
+
+ va_end(marker);
+}
+
+//
+// Same error message for all places assignments don't work.
+//
+void TParseContext::assignError(int line, const char* op, TString left, TString right)
+{
+ error(line, "", op, "cannot convert from '%s' to '%s'",
+ right.c_str(), left.c_str());
+}
+
+//
+// Same error message for all places unary operations don't work.
+//
+void TParseContext::unaryOpError(int line, const char* op, TString operand)
+{
+ error(line, " wrong operand type", op,
+ "no operation '%s' exists that takes an operand of type %s (or there is no acceptable conversion)",
+ op, operand.c_str());
+}
+
+//
+// Same error message for all binary operations don't work.
+//
+void TParseContext::binaryOpError(int line, const char* op, TString left, TString right)
+{
+ error(line, " wrong operand types ", op,
+ "no operation '%s' exists that takes a left-hand operand of type '%s' and "
+ "a right operand of type '%s' (or there is no acceptable conversion)",
+ op, left.c_str(), right.c_str());
+}
+
+bool TParseContext::precisionErrorCheck(int line, TPrecision precision, TBasicType type){
+ if (!checksPrecisionErrors)
+ return false;
+ switch( type ){
+ case EbtFloat:
+ if( precision == EbpUndefined ){
+ error( line, "No precision specified for (float)", "", "" );
+ return true;
+ }
+ break;
+ case EbtInt:
+ if( precision == EbpUndefined ){
+ error( line, "No precision specified (int)", "", "" );
+ return true;
+ }
+ break;
+ default:
+ return false;
+ }
+ return false;
+}
+
+//
+// Both test and if necessary, spit out an error, to see if the node is really
+// an l-value that can be operated on this way.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* node)
+{
+ TIntermSymbol* symNode = node->getAsSymbolNode();
+ TIntermBinary* binaryNode = node->getAsBinaryNode();
+
+ if (binaryNode) {
+ bool errorReturn;
+
+ switch(binaryNode->getOp()) {
+ case EOpIndexDirect:
+ case EOpIndexIndirect:
+ case EOpIndexDirectStruct:
+ return lValueErrorCheck(line, op, binaryNode->getLeft());
+ case EOpVectorSwizzle:
+ errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
+ if (!errorReturn) {
+ int offset[4] = {0,0,0,0};
+
+ TIntermTyped* rightNode = binaryNode->getRight();
+ TIntermAggregate *aggrNode = rightNode->getAsAggregate();
+
+ for (TIntermSequence::iterator p = aggrNode->getSequence().begin();
+ p != aggrNode->getSequence().end(); p++) {
+ int value = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getIConst();
+ offset[value]++;
+ if (offset[value] > 1) {
+ error(line, " l-value of swizzle cannot have duplicate components", op, "", "");
+
+ return true;
+ }
+ }
+ }
+
+ return errorReturn;
+ default:
+ break;
+ }
+ error(line, " l-value required", op, "", "");
+
+ return true;
+ }
+
+
+ const char* symbol = 0;
+ if (symNode != 0)
+ symbol = symNode->getSymbol().c_str();
+
+ const char* message = 0;
+ switch (node->getQualifier()) {
+ case EvqConst: message = "can't modify a const"; break;
+ case EvqConstReadOnly: message = "can't modify a const"; break;
+ case EvqAttribute: message = "can't modify an attribute"; break;
+ case EvqUniform: message = "can't modify a uniform"; break;
+ case EvqVaryingIn: message = "can't modify a varying"; break;
+ case EvqInput: message = "can't modify an input"; break;
+ case EvqFragCoord: message = "can't modify gl_FragCoord"; break;
+ case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break;
+ case EvqPointCoord: message = "can't modify gl_PointCoord"; break;
+ default:
+
+ //
+ // Type that can't be written to?
+ //
+ switch (node->getBasicType()) {
+ case EbtSampler2D:
+ case EbtSamplerCube:
+ message = "can't modify a sampler";
+ break;
+ case EbtVoid:
+ message = "can't modify void";
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (message == 0 && binaryNode == 0 && symNode == 0) {
+ error(line, " l-value required", op, "", "");
+
+ return true;
+ }
+
+
+ //
+ // Everything else is okay, no error.
+ //
+ if (message == 0)
+ return false;
+
+ //
+ // If we get here, we have an error and a message.
+ //
+ if (symNode)
+ error(line, " l-value required", op, "\"%s\" (%s)", symbol, message);
+ else
+ error(line, " l-value required", op, "(%s)", message);
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// a constant.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::constErrorCheck(TIntermTyped* node)
+{
+ if (node->getQualifier() == EvqConst)
+ return false;
+
+ error(node->getLine(), "constant expression required", "", "");
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if the node is really
+// an integer.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token)
+{
+ if (node->getBasicType() == EbtInt && node->getNominalSize() == 1)
+ return false;
+
+ error(node->getLine(), "integer expression required", token, "");
+
+ return true;
+}
+
+//
+// Both test, and if necessary spit out an error, to see if we are currently
+// globally scoped.
+//
+// Returns true if the was an error.
+//
+bool TParseContext::globalErrorCheck(int line, bool global, const char* token)
+{
+ if (global)
+ return false;
+
+ error(line, "only allowed at global scope", token, "");
+
+ return true;
+}
+
+//
+// For now, keep it simple: if it starts "gl_", it's reserved, independent
+// of scope. Except, if the symbol table is at the built-in push-level,
+// which is when we are parsing built-ins.
+// Also checks for "webgl_" and "_webgl_" reserved identifiers if parsing a
+// webgl shader.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::reservedErrorCheck(int line, const TString& identifier)
+{
+ static const char* reservedErrMsg = "reserved built-in name";
+ if (!symbolTable.atBuiltInLevel()) {
+ if (identifier.substr(0, 3) == TString("gl_")) {
+ error(line, reservedErrMsg, "gl_", "");
+ return true;
+ }
+ if (shaderSpec == SH_WEBGL_SPEC) {
+ if (identifier.substr(0, 6) == TString("webgl_")) {
+ error(line, reservedErrMsg, "webgl_", "");
+ return true;
+ }
+ if (identifier.substr(0, 7) == TString("_webgl_")) {
+ error(line, reservedErrMsg, "_webgl_", "");
+ return true;
+ }
+ }
+ if (identifier.find("__") != TString::npos) {
+ //error(line, "Two consecutive underscores are reserved for future use.", identifier.c_str(), "", "");
+ //return true;
+ infoSink.info.message(EPrefixWarning, "Two consecutive underscores are reserved for future use.", line);
+ return false;
+ }
+ }
+
+ return false;
+}
+
+//
+// Make sure there is enough data provided to the constructor to build
+// something of the type of the constructor. Also returns the type of
+// the constructor.
+//
+// Returns true if there was an error in construction.
+//
+bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction& function, TOperator op, TType* type)
+{
+ *type = function.getReturnType();
+
+ bool constructingMatrix = false;
+ switch(op) {
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ constructingMatrix = true;
+ break;
+ default:
+ break;
+ }
+
+ //
+ // Note: It's okay to have too many components available, but not okay to have unused
+ // arguments. 'full' will go to true when enough args have been seen. If we loop
+ // again, there is an extra argument, so 'overfull' will become true.
+ //
+
+ int size = 0;
+ bool constType = true;
+ bool full = false;
+ bool overFull = false;
+ bool matrixInMatrix = false;
+ bool arrayArg = false;
+ for (int i = 0; i < function.getParamCount(); ++i) {
+ const TParameter& param = function.getParam(i);
+ size += param.type->getObjectSize();
+
+ if (constructingMatrix && param.type->isMatrix())
+ matrixInMatrix = true;
+ if (full)
+ overFull = true;
+ if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize())
+ full = true;
+ if (param.type->getQualifier() != EvqConst)
+ constType = false;
+ if (param.type->isArray())
+ arrayArg = true;
+ }
+
+ if (constType)
+ type->setQualifier(EvqConst);
+
+ if (type->isArray() && type->getArraySize() != function.getParamCount()) {
+ error(line, "array constructor needs one argument per array element", "constructor", "");
+ return true;
+ }
+
+ if (arrayArg && op != EOpConstructStruct) {
+ error(line, "constructing from a non-dereferenced array", "constructor", "");
+ return true;
+ }
+
+ if (matrixInMatrix && !type->isArray()) {
+ if (function.getParamCount() != 1) {
+ error(line, "constructing matrix from matrix can only take one argument", "constructor", "");
+ return true;
+ }
+ }
+
+ if (overFull) {
+ error(line, "too many arguments", "constructor", "");
+ return true;
+ }
+
+ if (op == EOpConstructStruct && !type->isArray() && int(type->getStruct()->size()) != function.getParamCount()) {
+ error(line, "Number of constructor parameters does not match the number of structure fields", "constructor", "");
+ return true;
+ }
+
+ if (!type->isMatrix()) {
+ if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) ||
+ (op == EOpConstructStruct && size < type->getObjectSize())) {
+ error(line, "not enough data provided for construction", "constructor", "");
+ return true;
+ }
+ }
+
+ TIntermTyped *typed = node ? node->getAsTyped() : 0;
+ if (typed == 0) {
+ error(line, "constructor argument does not have a type", "constructor", "");
+ return true;
+ }
+ if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) {
+ error(line, "cannot convert a sampler", "constructor", "");
+ return true;
+ }
+ if (typed->getBasicType() == EbtVoid) {
+ error(line, "cannot convert a void", "constructor", "");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if a void variable has been declared and raise an error message for such a case
+//
+// returns true in case of an error
+//
+bool TParseContext::voidErrorCheck(int line, const TString& identifier, const TPublicType& pubType)
+{
+ if (pubType.type == EbtVoid) {
+ error(line, "illegal use of type 'void'", identifier.c_str(), "");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+//
+// returns true in case of an error
+//
+bool TParseContext::boolErrorCheck(int line, const TIntermTyped* type)
+{
+ if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) {
+ error(line, "boolean expression expected", "", "");
+ return true;
+ }
+
+ return false;
+}
+
+// This function checks to see if the node (for the expression) contains a scalar boolean expression or not
+//
+// returns true in case of an error
+//
+bool TParseContext::boolErrorCheck(int line, const TPublicType& pType)
+{
+ if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) {
+ error(line, "boolean expression expected", "", "");
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const char* reason)
+{
+ if (pType.type == EbtStruct) {
+ if (containsSampler(*pType.userDef)) {
+ error(line, reason, getBasicString(pType.type), "(structure contains a sampler)");
+
+ return true;
+ }
+
+ return false;
+ } else if (IsSampler(pType.type)) {
+ error(line, reason, getBasicString(pType.type), "");
+
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType)
+{
+ if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) &&
+ pType.type == EbtStruct) {
+ error(line, "cannot be used with a structure", getQualifierString(pType.qualifier), "");
+
+ return true;
+ }
+
+ if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type)
+{
+ if ((qualifier == EvqOut || qualifier == EvqInOut) &&
+ type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) {
+ error(line, "samplers cannot be output parameters", type.getBasicString(), "");
+ return true;
+ }
+
+ return false;
+}
+
+bool TParseContext::containsSampler(TType& type)
+{
+ if (IsSampler(type.getBasicType()))
+ return true;
+
+ if (type.getBasicType() == EbtStruct) {
+ TTypeList& structure = *type.getStruct();
+ for (unsigned int i = 0; i < structure.size(); ++i) {
+ if (containsSampler(*structure[i].type))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Do size checking for an array type's size.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size)
+{
+ TIntermConstantUnion* constant = expr->getAsConstantUnion();
+ if (constant == 0 || constant->getBasicType() != EbtInt) {
+ error(line, "array size must be a constant integer expression", "", "");
+ return true;
+ }
+
+ size = constant->getUnionArrayPointer()->getIConst();
+
+ if (size <= 0) {
+ error(line, "array size must be a positive integer", "", "");
+ size = 1;
+ return true;
+ }
+
+ return false;
+}
+
+//
+// See if this qualifier can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type)
+{
+ if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConst)) {
+ error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str(), "");
+ return true;
+ }
+
+ return false;
+}
+
+//
+// See if this type can be an array.
+//
+// Returns true if there is an error.
+//
+bool TParseContext::arrayTypeErrorCheck(int line, TPublicType type)
+{
+ //
+ // Can the type be an array?
+ //
+ if (type.array) {
+ error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str(), "");
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Do all the semantic checking for declaring an array, with and
+// without a size, and make the right changes to the symbol table.
+//
+// size == 0 means no specified size.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable)
+{
+ //
+ // Don't check for reserved word use until after we know it's not in the symbol table,
+ // because reserved arrays can be redeclared.
+ //
+
+ bool builtIn = false;
+ bool sameScope = false;
+ TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope);
+ if (symbol == 0 || !sameScope) {
+ if (reservedErrorCheck(line, identifier))
+ return true;
+
+ variable = new TVariable(&identifier, TType(type));
+
+ if (type.arraySize)
+ variable->getType().setArraySize(type.arraySize);
+
+ if (! symbolTable.insert(*variable)) {
+ delete variable;
+ error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str(), "");
+ return true;
+ }
+ } else {
+ if (! symbol->isVariable()) {
+ error(line, "variable expected", identifier.c_str(), "");
+ return true;
+ }
+
+ variable = static_cast<TVariable*>(symbol);
+ if (! variable->getType().isArray()) {
+ error(line, "redeclaring non-array as array", identifier.c_str(), "");
+ return true;
+ }
+ if (variable->getType().getArraySize() > 0) {
+ error(line, "redeclaration of array with size", identifier.c_str(), "");
+ return true;
+ }
+
+ if (! variable->getType().sameElementType(TType(type))) {
+ error(line, "redeclaration of array with a different type", identifier.c_str(), "");
+ return true;
+ }
+
+ TType* t = variable->getArrayInformationType();
+ while (t != 0) {
+ if (t->getMaxArraySize() > type.arraySize) {
+ error(line, "higher index value already used for the array", identifier.c_str(), "");
+ return true;
+ }
+ t->setArraySize(type.arraySize);
+ t = t->getArrayInformationType();
+ }
+
+ if (type.arraySize)
+ variable->getType().setArraySize(type.arraySize);
+ }
+
+ if (voidErrorCheck(line, identifier, type))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc line)
+{
+ bool builtIn = false;
+ TSymbol* symbol = symbolTable.find(node->getSymbol(), &builtIn);
+ if (symbol == 0) {
+ error(line, " undeclared identifier", node->getSymbol().c_str(), "");
+ return true;
+ }
+ TVariable* variable = static_cast<TVariable*>(symbol);
+
+ type->setArrayInformationType(variable->getArrayInformationType());
+ variable->updateArrayInformationType(type);
+
+ // special casing to test index value of gl_FragData. If the accessed index is >= gl_MaxDrawBuffers
+ // its an error
+ if (node->getSymbol() == "gl_FragData") {
+ TSymbol* fragData = symbolTable.find("gl_MaxDrawBuffers", &builtIn);
+ if (fragData == 0) {
+ infoSink.info.message(EPrefixInternalError, "gl_MaxDrawBuffers not defined", line);
+ return true;
+ }
+
+ int fragDataValue = static_cast<TVariable*>(fragData)->getConstPointer()[0].getIConst();
+ if (fragDataValue <= size) {
+ error(line, "", "[", "gl_FragData can only have a max array size of up to gl_MaxDrawBuffers", "");
+ return true;
+ }
+ }
+
+ // we dont want to update the maxArraySize when this flag is not set, we just want to include this
+ // node type in the chain of node types so that its updated when a higher maxArraySize comes in.
+ if (!updateFlag)
+ return false;
+
+ size++;
+ variable->getType().setMaxArraySize(size);
+ type->setMaxArraySize(size);
+ TType* tt = type;
+
+ while(tt->getArrayInformationType() != 0) {
+ tt = tt->getArrayInformationType();
+ tt->setMaxArraySize(size);
+ }
+
+ return false;
+}
+
+//
+// Enforce non-initializer type/qualifier rules.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type)
+{
+ //
+ // Make the qualifier make sense.
+ //
+ if (type.qualifier == EvqConst) {
+ type.qualifier = EvqTemporary;
+ error(line, "variables with qualifier 'const' must be initialized", identifier.c_str(), "");
+ return true;
+ }
+
+ return false;
+}
+
+//
+// Do semantic checking for a variable declaration that has no initializer,
+// and update the symbol table.
+//
+// Returns true if there was an error.
+//
+bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable)
+{
+ if (reservedErrorCheck(line, identifier))
+ recover();
+
+ variable = new TVariable(&identifier, TType(type));
+
+ if (! symbolTable.insert(*variable)) {
+ error(line, "redefinition", variable->getName().c_str(), "");
+ delete variable;
+ variable = 0;
+ return true;
+ }
+
+ if (voidErrorCheck(line, identifier, type))
+ return true;
+
+ return false;
+}
+
+bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type)
+{
+ if (qualifier != EvqConst && qualifier != EvqTemporary) {
+ error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier), "");
+ return true;
+ }
+ if (qualifier == EvqConst && paramQualifier != EvqIn) {
+ error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier));
+ return true;
+ }
+
+ if (qualifier == EvqConst)
+ type->setQualifier(EvqConstReadOnly);
+ else
+ type->setQualifier(paramQualifier);
+
+ return false;
+}
+
+bool TParseContext::extensionErrorCheck(int line, const TString& extension)
+{
+ TExtensionBehavior::const_iterator iter = extensionBehavior.find(extension);
+ if (iter == extensionBehavior.end()) {
+ error(line, "extension", extension.c_str(), "is not supported");
+ return true;
+ }
+ if (iter->second == EBhDisable) {
+ error(line, "extension", extension.c_str(), "is disabled");
+ return true;
+ }
+ if (iter->second == EBhWarn) {
+ TString msg = "extension " + extension + " is being used";
+ infoSink.info.message(EPrefixWarning, msg.c_str(), line);
+ return false;
+ }
+
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//
+// Non-Errors.
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+//
+// Look up a function name in the symbol table, and make sure it is a function.
+//
+// Return the function symbol if found, otherwise 0.
+//
+const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *builtIn)
+{
+ // First find by unmangled name to check whether the function name has been
+ // hidden by a variable name or struct typename.
+ const TSymbol* symbol = symbolTable.find(call->getName(), builtIn);
+ if (symbol == 0) {
+ symbol = symbolTable.find(call->getMangledName(), builtIn);
+ }
+
+ if (symbol == 0) {
+ error(line, "no matching overloaded function found", call->getName().c_str(), "");
+ return 0;
+ }
+
+ if (!symbol->isFunction()) {
+ error(line, "function name expected", call->getName().c_str(), "");
+ return 0;
+ }
+
+ return static_cast<const TFunction*>(symbol);
+}
+
+//
+// Initializers show up in several places in the grammar. Have one set of
+// code to handle them here.
+//
+bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
+ TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable)
+{
+ TType type = TType(pType);
+
+ if (variable == 0) {
+ if (reservedErrorCheck(line, identifier))
+ return true;
+
+ if (voidErrorCheck(line, identifier, pType))
+ return true;
+
+ //
+ // add variable to symbol table
+ //
+ variable = new TVariable(&identifier, type);
+ if (! symbolTable.insert(*variable)) {
+ error(line, "redefinition", variable->getName().c_str(), "");
+ return true;
+ // don't delete variable, it's used by error recovery, and the pool
+ // pop will take care of the memory
+ }
+ }
+
+ //
+ // identifier must be of type constant, a global, or a temporary
+ //
+ TQualifier qualifier = variable->getType().getQualifier();
+ if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) {
+ error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString(), "");
+ return true;
+ }
+ //
+ // test for and propagate constant
+ //
+
+ if (qualifier == EvqConst) {
+ if (qualifier != initializer->getType().getQualifier()) {
+ error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (type != initializer->getType()) {
+ error(line, " non-matching types for const initializer ",
+ variable->getType().getQualifierString(), "");
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ if (initializer->getAsConstantUnion()) {
+ ConstantUnion* unionArray = variable->getConstPointer();
+
+ if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) {
+ *unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0];
+ } else {
+ variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer());
+ }
+ } else if (initializer->getAsSymbolNode()) {
+ const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol());
+ const TVariable* tVar = static_cast<const TVariable*>(symbol);
+
+ ConstantUnion* constArray = tVar->getConstPointer();
+ variable->shareConstPointer(constArray);
+ } else {
+ error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str());
+ variable->getType().setQualifier(EvqTemporary);
+ return true;
+ }
+ }
+
+ if (qualifier != EvqConst) {
+ TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line);
+ intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line);
+ if (intermNode == 0) {
+ assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
+ return true;
+ }
+ } else
+ intermNode = 0;
+
+ return false;
+}
+
+bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
+{
+ ASSERT(aggrNode != NULL);
+ if (!aggrNode->isConstructor())
+ return false;
+
+ bool allConstant = true;
+
+ // check if all the child nodes are constants so that they can be inserted into
+ // the parent node
+ TIntermSequence &sequence = aggrNode->getSequence() ;
+ for (TIntermSequence::iterator p = sequence.begin(); p != sequence.end(); ++p) {
+ if (!(*p)->getAsTyped()->getAsConstantUnion())
+ return false;
+ }
+
+ return allConstant;
+}
+
+// This function is used to test for the correctness of the parameters passed to various constructor functions
+// and also convert them to the right datatype if it is allowed and required.
+//
+// Returns 0 for an error or the constructed node (aggregate or typed) for no error.
+//
+TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line)
+{
+ if (node == 0)
+ return 0;
+
+ TIntermAggregate* aggrNode = node->getAsAggregate();
+
+ TTypeList::const_iterator memberTypes;
+ if (op == EOpConstructStruct)
+ memberTypes = type->getStruct()->begin();
+
+ TType elementType = *type;
+ if (type->isArray())
+ elementType.clearArrayness();
+
+ bool singleArg;
+ if (aggrNode) {
+ if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1)
+ singleArg = true;
+ else
+ singleArg = false;
+ } else
+ singleArg = true;
+
+ TIntermTyped *newNode;
+ if (singleArg) {
+ // If structure constructor or array constructor is being called
+ // for only one parameter inside the structure, we need to call constructStruct function once.
+ if (type->isArray())
+ newNode = constructStruct(node, &elementType, 1, node->getLine(), false);
+ else if (op == EOpConstructStruct)
+ newNode = constructStruct(node, (*memberTypes).type, 1, node->getLine(), false);
+ else
+ newNode = constructBuiltIn(type, op, node, node->getLine(), false);
+
+ if (newNode && newNode->getAsAggregate()) {
+ TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type);
+ if (constConstructor)
+ return constConstructor;
+ }
+
+ return newNode;
+ }
+
+ //
+ // Handle list of arguments.
+ //
+ TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor
+ // if the structure constructor contains more than one parameter, then construct
+ // each parameter
+
+ int paramCount = 0; // keeps a track of the constructor parameter number being checked
+
+ // for each parameter to the constructor call, check to see if the right type is passed or convert them
+ // to the right type if possible (and allowed).
+ // for structure constructors, just check if the right type is passed, no conversion is allowed.
+
+ for (TIntermSequence::iterator p = sequenceVector.begin();
+ p != sequenceVector.end(); p++, paramCount++) {
+ if (type->isArray())
+ newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true);
+ else if (op == EOpConstructStruct)
+ newNode = constructStruct(*p, (memberTypes[paramCount]).type, paramCount+1, node->getLine(), true);
+ else
+ newNode = constructBuiltIn(type, op, *p, node->getLine(), true);
+
+ if (newNode) {
+ *p = newNode;
+ }
+ }
+
+ TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line);
+ TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type);
+ if (constConstructor)
+ return constConstructor;
+
+ return constructor;
+}
+
+TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type)
+{
+ bool canBeFolded = areAllChildConst(aggrNode);
+ aggrNode->setType(type);
+ if (canBeFolded) {
+ bool returnVal = false;
+ ConstantUnion* unionArray = new ConstantUnion[type.getObjectSize()];
+ if (aggrNode->getSequence().size() == 1) {
+ returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true);
+ }
+ else {
+ returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type);
+ }
+ if (returnVal)
+ return 0;
+
+ return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine());
+ }
+
+ return 0;
+}
+
+// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value
+// for the parameter to the constructor (passed to this function). Essentially, it converts
+// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a
+// float, then float is converted to int.
+//
+// Returns 0 for an error or the constructed node.
+//
+TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, TSourceLoc line, bool subset)
+{
+ TIntermTyped* newNode;
+ TOperator basicOp;
+
+ //
+ // First, convert types as needed.
+ //
+ switch (op) {
+ case EOpConstructVec2:
+ case EOpConstructVec3:
+ case EOpConstructVec4:
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4:
+ case EOpConstructFloat:
+ basicOp = EOpConstructFloat;
+ break;
+
+ case EOpConstructIVec2:
+ case EOpConstructIVec3:
+ case EOpConstructIVec4:
+ case EOpConstructInt:
+ basicOp = EOpConstructInt;
+ break;
+
+ case EOpConstructBVec2:
+ case EOpConstructBVec3:
+ case EOpConstructBVec4:
+ case EOpConstructBool:
+ basicOp = EOpConstructBool;
+ break;
+
+ default:
+ error(line, "unsupported construction", "", "");
+ recover();
+
+ return 0;
+ }
+ newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable);
+ if (newNode == 0) {
+ error(line, "can't convert", "constructor", "");
+ return 0;
+ }
+
+ //
+ // Now, if there still isn't an operation to do the construction, and we need one, add one.
+ //
+
+ // Otherwise, skip out early.
+ if (subset || (newNode != node && newNode->getType() == *type))
+ return newNode;
+
+ // setAggregateOperator will insert a new node for the constructor, as needed.
+ return intermediate.setAggregateOperator(newNode, op, line);
+}
+
+// This function tests for the type of the parameters to the structures constructors. Raises
+// an error message if the expected type does not match the parameter passed to the constructor.
+//
+// Returns 0 for an error or the input node itself if the expected and the given parameter types match.
+//
+TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, TSourceLoc line, bool subset)
+{
+ if (*type == node->getAsTyped()->getType()) {
+ if (subset)
+ return node->getAsTyped();
+ else
+ return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line);
+ } else {
+ error(line, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount,
+ node->getAsTyped()->getType().getBasicString(), type->getBasicString());
+ recover();
+ }
+
+ return 0;
+}
+
+//
+// This function returns the tree representation for the vector field(s) being accessed from contant vector.
+// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is
+// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol
+// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of
+// a constant matrix.
+//
+TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+
+ ConstantUnion *unionArray;
+ if (tempConstantNode) {
+ unionArray = tempConstantNode->getUnionArrayPointer();
+
+ if (!unionArray) { // this error message should never be raised
+ infoSink.info.message(EPrefixInternalError, "ConstantUnion not initialized in addConstVectorNode function", line);
+ recover();
+
+ return node;
+ }
+ } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error
+ error(line, "Cannot offset into the vector", "Error", "");
+ recover();
+
+ return 0;
+ }
+
+ ConstantUnion* constArray = new ConstantUnion[fields.num];
+
+ for (int i = 0; i < fields.num; i++) {
+ if (fields.offsets[i] >= node->getType().getObjectSize()) {
+ error(line, "", "[", "vector field selection out of range '%d'", fields.offsets[i]);
+ recover();
+ fields.offsets[i] = 0;
+ }
+
+ constArray[i] = unionArray[fields.offsets[i]];
+
+ }
+ typedNode = intermediate.addConstantUnion(constArray, node->getType(), line);
+ return typedNode;
+}
+
+//
+// This function returns the column being accessed from a constant matrix. The values are retrieved from
+// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input
+// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a
+// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure)
+//
+TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+
+ if (index >= node->getType().getNominalSize()) {
+ error(line, "", "[", "matrix field selection out of range '%d'", index);
+ recover();
+ index = 0;
+ }
+
+ if (tempConstantNode) {
+ ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
+ int size = tempConstantNode->getType().getNominalSize();
+ typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line);
+ } else {
+ error(line, "Cannot offset into the matrix", "Error", "");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+
+//
+// This function returns an element of an array accessed from a constant array. The values are retrieved from
+// the symbol table and parse-tree is built for the type of the element. The input
+// to the function could either be a symbol node (a[0] where a is a constant array)that represents a
+// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure)
+//
+TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line)
+{
+ TIntermTyped* typedNode;
+ TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion();
+ TType arrayElementType = node->getType();
+ arrayElementType.clearArrayness();
+
+ if (index >= node->getType().getArraySize()) {
+ error(line, "", "[", "array field selection out of range '%d'", index);
+ recover();
+ index = 0;
+ }
+
+ int arrayElementSize = arrayElementType.getObjectSize();
+
+ if (tempConstantNode) {
+ ConstantUnion* unionArray = tempConstantNode->getUnionArrayPointer();
+ typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line);
+ } else {
+ error(line, "Cannot offset into the array", "Error", "");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+
+//
+// This function returns the value of a particular field inside a constant structure from the symbol table.
+// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr
+// function and returns the parse-tree with the values of the embedded/nested struct.
+//
+TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, TSourceLoc line)
+{
+ const TTypeList* fields = node->getType().getStruct();
+ TIntermTyped *typedNode;
+ int instanceSize = 0;
+ unsigned int index = 0;
+ TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion();
+
+ for ( index = 0; index < fields->size(); ++index) {
+ if ((*fields)[index].type->getFieldName() == identifier) {
+ break;
+ } else {
+ instanceSize += (*fields)[index].type->getObjectSize();
+ }
+ }
+
+ if (tempConstantNode) {
+ ConstantUnion* constArray = tempConstantNode->getUnionArrayPointer();
+
+ typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function
+ } else {
+ error(line, "Cannot offset into the structure", "Error", "");
+ recover();
+
+ return 0;
+ }
+
+ return typedNode;
+}
+
+//
+// Parse an array of strings using yyparse.
+//
+// Returns 0 for success.
+//
+int PaParseStrings(int count, const char* const string[], const int length[],
+ TParseContext* context) {
+ if ((count == 0) || (string == NULL))
+ return 1;
+
+ // setup preprocessor.
+ if (InitPreprocessor())
+ return 1;
+ DefineExtensionMacros(context->extensionBehavior);
+
+ if (glslang_initialize(context))
+ return 1;
+
+ glslang_scan(count, string, length, context);
+ int error = glslang_parse(context);
+
+ glslang_finalize(context);
+ FinalizePreprocessor();
+ return (error == 0) && (context->numErrors == 0) ? 0 : 1;
+}
+
+OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
+
+bool InitializeParseContextIndex()
+{
+ if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
+ return false;
+ }
+
+ //
+ // Allocate a TLS index.
+ //
+ GlobalParseContextIndex = OS_AllocTLSIndex();
+
+ if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
+ return false;
+ }
+
+ return true;
+}
+
+bool FreeParseContextIndex()
+{
+ OS_TLSIndex tlsiIndex = GlobalParseContextIndex;
+
+ if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "FreeParseContextIndex(): Parse Context index not initalised");
+ return false;
+ }
+
+ GlobalParseContextIndex = OS_INVALID_TLS_INDEX;
+
+ return OS_FreeTLSIndex(tlsiIndex);
+}
+
+bool InitializeGlobalParseContext()
+{
+ if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalised");
+ return false;
+ }
+
+ TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
+ if (lpParseContext != 0) {
+ assert(0 && "InitializeParseContextIndex(): Parse Context already initalised");
+ return false;
+ }
+
+ TThreadParseContext *lpThreadData = new TThreadParseContext();
+ if (lpThreadData == 0) {
+ assert(0 && "InitializeGlobalParseContext(): Unable to create thread parse context");
+ return false;
+ }
+
+ lpThreadData->lpGlobalParseContext = 0;
+ OS_SetTLSValue(GlobalParseContextIndex, lpThreadData);
+
+ return true;
+}
+
+bool FreeParseContext()
+{
+ if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "FreeParseContext(): Parse Context index not initalised");
+ return false;
+ }
+
+ TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
+ if (lpParseContext)
+ delete lpParseContext;
+
+ return true;
+}
+
+TParseContextPointer& GetGlobalParseContext()
+{
+ //
+ // Minimal error checking for speed
+ //
+
+ TThreadParseContext *lpParseContext = static_cast<TThreadParseContext *>(OS_GetTLSValue(GlobalParseContextIndex));
+
+ return lpParseContext->lpGlobalParseContext;
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ParseHelper.h b/Source/ThirdParty/ANGLE/src/compiler/ParseHelper.h
new file mode 100644
index 000000000..8637d890b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ParseHelper.h
@@ -0,0 +1,119 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef _PARSER_HELPER_INCLUDED_
+#define _PARSER_HELPER_INCLUDED_
+
+#include "compiler/ExtensionBehavior.h"
+#include "compiler/localintermediate.h"
+#include "compiler/ShHandle.h"
+#include "compiler/SymbolTable.h"
+
+struct TMatrixFields {
+ bool wholeRow;
+ bool wholeCol;
+ int row;
+ int col;
+};
+
+struct TPragma {
+ TPragma(bool o, bool d) : optimize(o), debug(d) { }
+ bool optimize;
+ bool debug;
+ TPragmaTable pragmaTable;
+};
+
+//
+// The following are extra variables needed during parsing, grouped together so
+// they can be passed to the parser without needing a global.
+//
+struct TParseContext {
+ TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, bool checksPrecErrors, const char* sourcePath, TInfoSink& is) :
+ intermediate(interm), symbolTable(symt), extensionBehavior(ext), infoSink(is), shaderType(type), shaderSpec(spec), compileOptions(options), checksPrecisionErrors(checksPrecErrors), sourcePath(sourcePath), treeRoot(0),
+ recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
+ inTypeParen(false), scanner(NULL), contextPragma(true, false) { }
+ TIntermediate& intermediate; // to hold and build a parse tree
+ TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
+ TExtensionBehavior& extensionBehavior; // mapping between supported extensions and current behavior.
+ TInfoSink& infoSink;
+ ShShaderType shaderType; // vertex or fragment language (future: pack or unpack)
+ ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
+ int compileOptions;
+ const char* sourcePath; // Path of source file or NULL.
+ TIntermNode* treeRoot; // root of parse tree being created
+ bool recoveredFromError; // true if a parse error has occurred, but we continue to parse
+ int numErrors;
+ bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier
+ int loopNestingLevel; // 0 if outside all loops
+ bool inTypeParen; // true if in parentheses, looking only for an identifier
+ const TType* currentFunctionType; // the return type of the function that's currently being parsed
+ bool functionReturnsValue; // true if a non-void function has a return
+ bool checksPrecisionErrors; // true if an error will be generated when a variable is declared without precision, explicit or implicit.
+
+ void error(TSourceLoc loc, const char *reason, const char* token,
+ const char* extraInfoFormat, ...);
+ void warning(TSourceLoc loc, const char* reason, const char* token,
+ const char* extraInfoFormat, ...);
+ bool reservedErrorCheck(int line, const TString& identifier);
+ void recover();
+
+ bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line);
+ bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, int line);
+ void assignError(int line, const char* op, TString left, TString right);
+ void unaryOpError(int line, const char* op, TString operand);
+ void binaryOpError(int line, const char* op, TString left, TString right);
+ bool precisionErrorCheck(int line, TPrecision precision, TBasicType type);
+ bool lValueErrorCheck(int line, const char* op, TIntermTyped*);
+ bool constErrorCheck(TIntermTyped* node);
+ bool integerErrorCheck(TIntermTyped* node, const char* token);
+ bool globalErrorCheck(int line, bool global, const char* token);
+ bool constructorErrorCheck(int line, TIntermNode*, TFunction&, TOperator, TType*);
+ bool arraySizeErrorCheck(int line, TIntermTyped* expr, int& size);
+ bool arrayQualifierErrorCheck(int line, TPublicType type);
+ bool arrayTypeErrorCheck(int line, TPublicType type);
+ bool arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable);
+ bool voidErrorCheck(int, const TString&, const TPublicType&);
+ bool boolErrorCheck(int, const TIntermTyped*);
+ bool boolErrorCheck(int, const TPublicType&);
+ bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason);
+ bool structQualifierErrorCheck(int line, const TPublicType& pType);
+ bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type);
+ bool containsSampler(TType& type);
+ bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type);
+ bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable);
+ bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
+ bool extensionErrorCheck(int line, const TString&);
+ const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
+ bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
+ TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
+ bool areAllChildConst(TIntermAggregate* aggrNode);
+ TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc);
+ TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type);
+ TIntermTyped* constructStruct(TIntermNode*, TType*, int, TSourceLoc, bool subset);
+ TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, TSourceLoc, bool subset);
+ TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc);
+ TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc);
+ TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line);
+ TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc);
+ bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc);
+ void* scanner;
+ struct TPragma contextPragma;
+ TString HashErrMsg;
+ bool AfterEOF;
+};
+
+int PaParseStrings(int count, const char* const string[], const int length[],
+ TParseContext* context);
+
+typedef TParseContext* TParseContextPointer;
+extern TParseContextPointer& GetGlobalParseContext();
+#define GlobalParseContext GetGlobalParseContext()
+
+typedef struct TThreadParseContextRec
+{
+ TParseContext *lpGlobalParseContext;
+} TThreadParseContext;
+
+#endif // _PARSER_HELPER_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.cpp b/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.cpp
new file mode 100644
index 000000000..e286c7d20
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.cpp
@@ -0,0 +1,304 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/PoolAlloc.h"
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+#include <stdio.h>
+
+#include "compiler/InitializeGlobals.h"
+#include "compiler/osinclude.h"
+
+OS_TLSIndex PoolIndex = OS_INVALID_TLS_INDEX;
+
+void InitializeGlobalPools()
+{
+ TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
+ if (globalPools)
+ return;
+
+ TThreadGlobalPools* threadData = new TThreadGlobalPools();
+ threadData->globalPoolAllocator = 0;
+
+ OS_SetTLSValue(PoolIndex, threadData);
+}
+
+void FreeGlobalPools()
+{
+ // Release the allocated memory for this thread.
+ TThreadGlobalPools* globalPools= static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
+ if (!globalPools)
+ return;
+
+ delete globalPools;
+}
+
+bool InitializePoolIndex()
+{
+ // Allocate a TLS index.
+ if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX)
+ return false;
+
+ return true;
+}
+
+void FreePoolIndex()
+{
+ // Release the TLS index.
+ OS_FreeTLSIndex(PoolIndex);
+}
+
+TPoolAllocator& GetGlobalPoolAllocator()
+{
+ TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
+
+ return *threadData->globalPoolAllocator;
+}
+
+void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator)
+{
+ TThreadGlobalPools* threadData = static_cast<TThreadGlobalPools*>(OS_GetTLSValue(PoolIndex));
+
+ threadData->globalPoolAllocator = poolAllocator;
+}
+
+//
+// Implement the functionality of the TPoolAllocator class, which
+// is documented in PoolAlloc.h.
+//
+TPoolAllocator::TPoolAllocator(int growthIncrement, int allocationAlignment) :
+ pageSize(growthIncrement),
+ alignment(allocationAlignment),
+ freeList(0),
+ inUseList(0),
+ numCalls(0),
+ totalBytes(0)
+{
+ //
+ // Don't allow page sizes we know are smaller than all common
+ // OS page sizes.
+ //
+ if (pageSize < 4*1024)
+ pageSize = 4*1024;
+
+ //
+ // A large currentPageOffset indicates a new page needs to
+ // be obtained to allocate memory.
+ //
+ currentPageOffset = pageSize;
+
+ //
+ // Adjust alignment to be at least pointer aligned and
+ // power of 2.
+ //
+ size_t minAlign = sizeof(void*);
+ alignment &= ~(minAlign - 1);
+ if (alignment < minAlign)
+ alignment = minAlign;
+ size_t a = 1;
+ while (a < alignment)
+ a <<= 1;
+ alignment = a;
+ alignmentMask = a - 1;
+
+ //
+ // Align header skip
+ //
+ headerSkip = minAlign;
+ if (headerSkip < sizeof(tHeader)) {
+ headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask;
+ }
+}
+
+TPoolAllocator::~TPoolAllocator()
+{
+ while (inUseList) {
+ tHeader* next = inUseList->nextPage;
+ inUseList->~tHeader();
+ delete [] reinterpret_cast<char*>(inUseList);
+ inUseList = next;
+ }
+
+ // We should not check the guard blocks
+ // here, because we did it already when the block was
+ // placed into the free list.
+ //
+ while (freeList) {
+ tHeader* next = freeList->nextPage;
+ delete [] reinterpret_cast<char*>(freeList);
+ freeList = next;
+ }
+}
+
+// Support MSVC++ 6.0
+const unsigned char TAllocation::guardBlockBeginVal = 0xfb;
+const unsigned char TAllocation::guardBlockEndVal = 0xfe;
+const unsigned char TAllocation::userDataFill = 0xcd;
+
+#ifdef GUARD_BLOCKS
+ const size_t TAllocation::guardBlockSize = 16;
+#else
+ const size_t TAllocation::guardBlockSize = 0;
+#endif
+
+//
+// Check a single guard block for damage
+//
+void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const
+{
+#ifdef GUARD_BLOCKS
+ for (size_t x = 0; x < guardBlockSize; x++) {
+ if (blockMem[x] != val) {
+ char assertMsg[80];
+
+ // We don't print the assert message. It's here just to be helpful.
+ sprintf(assertMsg, "PoolAlloc: Damage %s %lu byte allocation at 0x%p\n",
+ locText, size, data());
+ assert(0 && "PoolAlloc: Damage in guard block");
+ }
+ }
+#endif
+}
+
+
+void TPoolAllocator::push()
+{
+ tAllocState state = { currentPageOffset, inUseList };
+
+ stack.push_back(state);
+
+ //
+ // Indicate there is no current page to allocate from.
+ //
+ currentPageOffset = pageSize;
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred since the last push(), or since the
+// last pop(), or since the object's creation.
+//
+// The deallocated pages are saved for future allocations.
+//
+void TPoolAllocator::pop()
+{
+ if (stack.size() < 1)
+ return;
+
+ tHeader* page = stack.back().page;
+ currentPageOffset = stack.back().offset;
+
+ while (inUseList != page) {
+ // invoke destructor to free allocation list
+ inUseList->~tHeader();
+
+ tHeader* nextInUse = inUseList->nextPage;
+ if (inUseList->pageCount > 1)
+ delete [] reinterpret_cast<char*>(inUseList);
+ else {
+ inUseList->nextPage = freeList;
+ freeList = inUseList;
+ }
+ inUseList = nextInUse;
+ }
+
+ stack.pop_back();
+}
+
+//
+// Do a mass-deallocation of all the individual allocations
+// that have occurred.
+//
+void TPoolAllocator::popAll()
+{
+ while (stack.size() > 0)
+ pop();
+}
+
+void* TPoolAllocator::allocate(size_t numBytes)
+{
+ // If we are using guard blocks, all allocations are bracketed by
+ // them: [guardblock][allocation][guardblock]. numBytes is how
+ // much memory the caller asked for. allocationSize is the total
+ // size including guard blocks. In release build,
+ // guardBlockSize=0 and this all gets optimized away.
+ size_t allocationSize = TAllocation::allocationSize(numBytes);
+
+ //
+ // Just keep some interesting statistics.
+ //
+ ++numCalls;
+ totalBytes += numBytes;
+
+ //
+ // Do the allocation, most likely case first, for efficiency.
+ // This step could be moved to be inline sometime.
+ //
+ if (currentPageOffset + allocationSize <= pageSize) {
+ //
+ // Safe to allocate from currentPageOffset.
+ //
+ unsigned char* memory = reinterpret_cast<unsigned char *>(inUseList) + currentPageOffset;
+ currentPageOffset += allocationSize;
+ currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, memory, numBytes);
+ }
+
+ if (allocationSize + headerSkip > pageSize) {
+ //
+ // Do a multi-page allocation. Don't mix these with the others.
+ // The OS is efficient and allocating and free-ing multiple pages.
+ //
+ size_t numBytesToAlloc = allocationSize + headerSkip;
+ tHeader* memory = reinterpret_cast<tHeader*>(::new char[numBytesToAlloc]);
+ if (memory == 0)
+ return 0;
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize);
+ inUseList = memory;
+
+ currentPageOffset = pageSize; // make next allocation come from a new page
+
+ // No guard blocks for multi-page allocations (yet)
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(memory) + headerSkip);
+ }
+
+ //
+ // Need a simple page to allocate from.
+ //
+ tHeader* memory;
+ if (freeList) {
+ memory = freeList;
+ freeList = freeList->nextPage;
+ } else {
+ memory = reinterpret_cast<tHeader*>(::new char[pageSize]);
+ if (memory == 0)
+ return 0;
+ }
+
+ // Use placement-new to initialize header
+ new(memory) tHeader(inUseList, 1);
+ inUseList = memory;
+
+ unsigned char* ret = reinterpret_cast<unsigned char *>(inUseList) + headerSkip;
+ currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask;
+
+ return initializeAllocation(inUseList, ret, numBytes);
+}
+
+
+//
+// Check all allocations in a list for damage by calling check on each.
+//
+void TAllocation::checkAllocList() const
+{
+ for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc)
+ alloc->check();
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.h b/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.h
new file mode 100644
index 000000000..55e09dbc4
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/PoolAlloc.h
@@ -0,0 +1,300 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _POOLALLOC_INCLUDED_
+#define _POOLALLOC_INCLUDED_
+
+#ifdef _DEBUG
+#define GUARD_BLOCKS // define to enable guard block sanity checking
+#endif
+
+//
+// This header defines an allocator that can be used to efficiently
+// allocate a large number of small requests for heap memory, with the
+// intention that they are not individually deallocated, but rather
+// collectively deallocated at one time.
+//
+// This simultaneously
+//
+// * Makes each individual allocation much more efficient; the
+// typical allocation is trivial.
+// * Completely avoids the cost of doing individual deallocation.
+// * Saves the trouble of tracking down and plugging a large class of leaks.
+//
+// Individual classes can use this allocator by supplying their own
+// new and delete methods.
+//
+// STL containers can use this allocator by using the pool_allocator
+// class as the allocator (second) template argument.
+//
+
+#include <stddef.h>
+#include <string.h>
+#include <vector>
+
+// If we are using guard blocks, we must track each indivual
+// allocation. If we aren't using guard blocks, these
+// never get instantiated, so won't have any impact.
+//
+
+class TAllocation {
+public:
+ TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) :
+ size(size), mem(mem), prevAlloc(prev) {
+ // Allocations are bracketed:
+ // [allocationHeader][initialGuardBlock][userData][finalGuardBlock]
+ // This would be cleaner with if (guardBlockSize)..., but that
+ // makes the compiler print warnings about 0 length memsets,
+ // even with the if() protecting them.
+#ifdef GUARD_BLOCKS
+ memset(preGuard(), guardBlockBeginVal, guardBlockSize);
+ memset(data(), userDataFill, size);
+ memset(postGuard(), guardBlockEndVal, guardBlockSize);
+#endif
+ }
+
+ void check() const {
+ checkGuardBlock(preGuard(), guardBlockBeginVal, "before");
+ checkGuardBlock(postGuard(), guardBlockEndVal, "after");
+ }
+
+ void checkAllocList() const;
+
+ // Return total size needed to accomodate user buffer of 'size',
+ // plus our tracking data.
+ inline static size_t allocationSize(size_t size) {
+ return size + 2 * guardBlockSize + headerSize();
+ }
+
+ // Offset from surrounding buffer to get to user data buffer.
+ inline static unsigned char* offsetAllocation(unsigned char* m) {
+ return m + guardBlockSize + headerSize();
+ }
+
+private:
+ void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const;
+
+ // Find offsets to pre and post guard blocks, and user data buffer
+ unsigned char* preGuard() const { return mem + headerSize(); }
+ unsigned char* data() const { return preGuard() + guardBlockSize; }
+ unsigned char* postGuard() const { return data() + size; }
+
+ size_t size; // size of the user data area
+ unsigned char* mem; // beginning of our allocation (pts to header)
+ TAllocation* prevAlloc; // prior allocation in the chain
+
+ // Support MSVC++ 6.0
+ const static unsigned char guardBlockBeginVal;
+ const static unsigned char guardBlockEndVal;
+ const static unsigned char userDataFill;
+
+ const static size_t guardBlockSize;
+#ifdef GUARD_BLOCKS
+ inline static size_t headerSize() { return sizeof(TAllocation); }
+#else
+ inline static size_t headerSize() { return 0; }
+#endif
+};
+
+//
+// There are several stacks. One is to track the pushing and popping
+// of the user, and not yet implemented. The others are simply a
+// repositories of free pages or used pages.
+//
+// Page stacks are linked together with a simple header at the beginning
+// of each allocation obtained from the underlying OS. Multi-page allocations
+// are returned to the OS. Individual page allocations are kept for future
+// re-use.
+//
+// The "page size" used is not, nor must it match, the underlying OS
+// page size. But, having it be about that size or equal to a set of
+// pages is likely most optimal.
+//
+class TPoolAllocator {
+public:
+ TPoolAllocator(int growthIncrement = 8*1024, int allocationAlignment = 16);
+
+ //
+ // Don't call the destructor just to free up the memory, call pop()
+ //
+ ~TPoolAllocator();
+
+ //
+ // Call push() to establish a new place to pop memory too. Does not
+ // have to be called to get things started.
+ //
+ void push();
+
+ //
+ // Call pop() to free all memory allocated since the last call to push(),
+ // or if no last call to push, frees all memory since first allocation.
+ //
+ void pop();
+
+ //
+ // Call popAll() to free all memory allocated.
+ //
+ void popAll();
+
+ //
+ // Call allocate() to actually acquire memory. Returns 0 if no memory
+ // available, otherwise a properly aligned pointer to 'numBytes' of memory.
+ //
+ void* allocate(size_t numBytes);
+
+ //
+ // There is no deallocate. The point of this class is that
+ // deallocation can be skipped by the user of it, as the model
+ // of use is to simultaneously deallocate everything at once
+ // by calling pop(), and to not have to solve memory leak problems.
+ //
+
+protected:
+ friend struct tHeader;
+
+ struct tHeader {
+ tHeader(tHeader* nextPage, size_t pageCount) :
+ nextPage(nextPage),
+ pageCount(pageCount)
+#ifdef GUARD_BLOCKS
+ , lastAllocation(0)
+#endif
+ { }
+
+ ~tHeader() {
+#ifdef GUARD_BLOCKS
+ if (lastAllocation)
+ lastAllocation->checkAllocList();
+#endif
+ }
+
+ tHeader* nextPage;
+ size_t pageCount;
+#ifdef GUARD_BLOCKS
+ TAllocation* lastAllocation;
+#endif
+ };
+
+ struct tAllocState {
+ size_t offset;
+ tHeader* page;
+ };
+ typedef std::vector<tAllocState> tAllocStack;
+
+ // Track allocations if and only if we're using guard blocks
+ void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) {
+#ifdef GUARD_BLOCKS
+ new(memory) TAllocation(numBytes, memory, block->lastAllocation);
+ block->lastAllocation = reinterpret_cast<TAllocation*>(memory);
+#endif
+ // This is optimized entirely away if GUARD_BLOCKS is not defined.
+ return TAllocation::offsetAllocation(memory);
+ }
+
+ size_t pageSize; // granularity of allocation from the OS
+ size_t alignment; // all returned allocations will be aligned at
+ // this granularity, which will be a power of 2
+ size_t alignmentMask;
+ size_t headerSkip; // amount of memory to skip to make room for the
+ // header (basically, size of header, rounded
+ // up to make it aligned
+ size_t currentPageOffset; // next offset in top of inUseList to allocate from
+ tHeader* freeList; // list of popped memory
+ tHeader* inUseList; // list of all memory currently being used
+ tAllocStack stack; // stack of where to allocate from, to partition pool
+
+ int numCalls; // just an interesting statistic
+ size_t totalBytes; // just an interesting statistic
+private:
+ TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator
+ TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor
+};
+
+
+//
+// There could potentially be many pools with pops happening at
+// different times. But a simple use is to have a global pop
+// with everyone using the same global allocator.
+//
+extern TPoolAllocator& GetGlobalPoolAllocator();
+extern void SetGlobalPoolAllocator(TPoolAllocator* poolAllocator);
+#define GlobalPoolAllocator GetGlobalPoolAllocator()
+
+struct TThreadGlobalPools
+{
+ TPoolAllocator* globalPoolAllocator;
+};
+
+//
+// This STL compatible allocator is intended to be used as the allocator
+// parameter to templatized STL containers, like vector and map.
+//
+// It will use the pools for allocation, and not
+// do any deallocation, but will still do destruction.
+//
+template<class T>
+class pool_allocator {
+public:
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T value_type;
+
+ template<class Other>
+ struct rebind {
+ typedef pool_allocator<Other> other;
+ };
+ pointer address(reference x) const { return &x; }
+ const_pointer address(const_reference x) const { return &x; }
+
+ pool_allocator() : allocator(GlobalPoolAllocator) { }
+ pool_allocator(TPoolAllocator& a) : allocator(a) { }
+ pool_allocator(const pool_allocator<T>& p) : allocator(p.allocator) { }
+
+ template<class Other>
+ pool_allocator(const pool_allocator<Other>& p) : allocator(p.getAllocator()) { }
+
+#if defined(__SUNPRO_CC) && !defined(_RWSTD_ALLOCATOR)
+ // libCStd on some platforms have a different allocate/deallocate interface.
+ // Caller pre-bakes sizeof(T) into 'n' which is the number of bytes to be
+ // allocated, not the number of elements.
+ void* allocate(size_type n) {
+ return getAllocator().allocate(n);
+ }
+ void* allocate(size_type n, const void*) {
+ return getAllocator().allocate(n);
+ }
+ void deallocate(void*, size_type) {}
+#else
+ pointer allocate(size_type n) {
+ return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ pointer allocate(size_type n, const void*) {
+ return reinterpret_cast<pointer>(getAllocator().allocate(n * sizeof(T)));
+ }
+ void deallocate(pointer, size_type) {}
+#endif // _RWSTD_ALLOCATOR
+
+ void construct(pointer p, const T& val) { new ((void *)p) T(val); }
+ void destroy(pointer p) { p->T::~T(); }
+
+ bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); }
+ bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); }
+
+ size_type max_size() const { return static_cast<size_type>(-1) / sizeof(T); }
+ size_type max_size(int size) const { return static_cast<size_type>(-1) / size; }
+
+ void setAllocator(TPoolAllocator* a) { allocator = *a; }
+ TPoolAllocator& getAllocator() const { return allocator; }
+
+protected:
+ TPoolAllocator& allocator;
+};
+
+#endif // _POOLALLOC_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.cpp b/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.cpp
new file mode 100644
index 000000000..92a6874eb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+
+class TAliveTraverser : public TIntermTraverser {
+public:
+ TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q)
+ {
+ }
+
+ bool wasFound() { return found; }
+
+protected:
+ bool found;
+ TQualifier qualifier;
+
+ void visitSymbol(TIntermSymbol*);
+ bool visitSelection(Visit, TIntermSelection*);
+};
+
+//
+// Report whether or not a variable of the given qualifier type
+// is guaranteed written. Not always possible to determine if
+// it is written conditionally.
+//
+// ?? It does not do this well yet, this is just a place holder
+// that simply determines if it was reference at all, anywhere.
+//
+bool QualifierWritten(TIntermNode* node, TQualifier qualifier)
+{
+ TAliveTraverser it(qualifier);
+
+ if (node)
+ node->traverse(&it);
+
+ return it.wasFound();
+}
+
+void TAliveTraverser::visitSymbol(TIntermSymbol* node)
+{
+ //
+ // If it's what we're looking for, record it.
+ //
+ if (node->getQualifier() == qualifier)
+ found = true;
+}
+
+bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node)
+{
+ if (wasFound())
+ return false;
+
+ return true;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.h b/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.h
new file mode 100644
index 000000000..872a06f72
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/QualifierAlive.h
@@ -0,0 +1,7 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+bool QualifierWritten(TIntermNode* root, TQualifier);
diff --git a/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.cpp b/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.cpp
new file mode 100644
index 000000000..a4b8c1e63
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/intermediate.h"
+#include "compiler/RemoveTree.h"
+
+//
+// Code to recursively delete the intermediate tree.
+//
+
+class RemoveTree : public TIntermTraverser
+{
+public:
+ RemoveTree() : TIntermTraverser(false, false, true)
+ {
+ }
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+};
+
+void RemoveTree::visitSymbol(TIntermSymbol* node)
+{
+ delete node;
+}
+
+bool RemoveTree::visitBinary(Visit visit, TIntermBinary* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitUnary(Visit visit, TIntermUnary* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ delete node;
+
+ return true;
+}
+
+bool RemoveTree::visitSelection(Visit visit, TIntermSelection* node)
+{
+ delete node;
+
+ return true;
+}
+
+void RemoveTree::visitConstantUnion(TIntermConstantUnion* node)
+{
+ delete node;
+}
+
+//
+// Entry point.
+//
+void RemoveAllTreeNodes(TIntermNode* root)
+{
+ RemoveTree it;
+
+ root->traverse(&it);
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.h b/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.h
new file mode 100644
index 000000000..97a821679
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/RemoveTree.h
@@ -0,0 +1,7 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+void RemoveAllTreeNodes(TIntermNode*);
diff --git a/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.cpp b/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.cpp
new file mode 100644
index 000000000..9368f1a4f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.cpp
@@ -0,0 +1,38 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SearchSymbol is an AST traverser to detect the use of a given symbol name
+//
+
+#include "compiler/SearchSymbol.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/OutputHLSL.h"
+
+namespace sh
+{
+SearchSymbol::SearchSymbol(const TString &symbol) : mSymbol(symbol)
+{
+ match = false;
+}
+
+void SearchSymbol::traverse(TIntermNode *node)
+{
+ node->traverse(this);
+}
+
+void SearchSymbol::visitSymbol(TIntermSymbol *symbolNode)
+{
+ if (symbolNode->getSymbol() == mSymbol)
+ {
+ match = true;
+ }
+}
+
+bool SearchSymbol::foundMatch() const
+{
+ return match;
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.h b/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.h
new file mode 100644
index 000000000..6bc0b90fe
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/SearchSymbol.h
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SearchSymbol is an AST traverser to detect the use of a given symbol name
+//
+
+#ifndef COMPILER_SEARCHSYMBOL_H_
+#define COMPILER_SEARCHSYMBOL_H_
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+class SearchSymbol : public TIntermTraverser
+{
+ public:
+ SearchSymbol(const TString &symbol);
+
+ void traverse(TIntermNode *node);
+ void visitSymbol(TIntermSymbol *symbolNode);
+
+ bool foundMatch() const;
+
+ protected:
+ const TString &mSymbol;
+ bool match;
+};
+}
+
+#endif // COMPILER_SEARCHSYMBOL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ShHandle.h b/Source/ThirdParty/ANGLE/src/compiler/ShHandle.h
new file mode 100644
index 000000000..bf61d29e5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ShHandle.h
@@ -0,0 +1,113 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _SHHANDLE_INCLUDED_
+#define _SHHANDLE_INCLUDED_
+
+//
+// Machine independent part of the compiler private objects
+// sent as ShHandle to the driver.
+//
+// This should not be included by driver code.
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/ExtensionBehavior.h"
+#include "compiler/InfoSink.h"
+#include "compiler/SymbolTable.h"
+#include "compiler/VariableInfo.h"
+
+class TCompiler;
+
+//
+// The base class used to back handles returned to the driver.
+//
+class TShHandleBase {
+public:
+ TShHandleBase();
+ virtual ~TShHandleBase();
+ virtual TCompiler* getAsCompiler() { return 0; }
+
+protected:
+ // Memory allocator. Allocates and tracks memory required by the compiler.
+ // Deallocates all memory when compiler is destructed.
+ TPoolAllocator allocator;
+};
+
+//
+// The base class for the machine dependent compiler to derive from
+// for managing object code from the compile.
+//
+class TCompiler : public TShHandleBase {
+public:
+ TCompiler(ShShaderType type, ShShaderSpec spec);
+ virtual ~TCompiler();
+ virtual TCompiler* getAsCompiler() { return this; }
+
+ bool Init(const ShBuiltInResources& resources);
+ bool compile(const char* const shaderStrings[],
+ const int numStrings,
+ int compileOptions);
+
+ // Get results of the last compilation.
+ TInfoSink& getInfoSink() { return infoSink; }
+ const TVariableInfoList& getAttribs() const { return attribs; }
+ const TVariableInfoList& getUniforms() const { return uniforms; }
+ int getMappedNameMaxLength() const;
+
+protected:
+ ShShaderType getShaderType() const { return shaderType; }
+ ShShaderSpec getShaderSpec() const { return shaderSpec; }
+ // Initialize symbol-table with built-in symbols.
+ bool InitBuiltInSymbolTable(const ShBuiltInResources& resources);
+ // Clears the results from the previous compilation.
+ void clearResults();
+ // Returns true if the given shader does not exceed the minimum
+ // functionality mandated in GLSL 1.0 spec Appendix A.
+ bool validateLimitations(TIntermNode* root);
+ // Collect info for all attribs and uniforms.
+ void collectAttribsUniforms(TIntermNode* root);
+ // Map long variable names into shorter ones.
+ void mapLongVariableNames(TIntermNode* root);
+ // Translate to object code.
+ virtual void translate(TIntermNode* root) = 0;
+ // Get built-in extensions with default behavior.
+ const TExtensionBehavior& getExtensionBehavior() const;
+
+private:
+ ShShaderType shaderType;
+ ShShaderSpec shaderSpec;
+
+ // Built-in symbol table for the given language, spec, and resources.
+ // It is preserved from compile-to-compile.
+ TSymbolTable symbolTable;
+ // Built-in extensions with default behavior.
+ TExtensionBehavior extensionBehavior;
+
+ // Results of compilation.
+ TInfoSink infoSink; // Output sink.
+ TVariableInfoList attribs; // Active attributes in the compiled shader.
+ TVariableInfoList uniforms; // Active uniforms in the compiled shader.
+
+ // Pair of long varying varibale name <originalName, mappedName>.
+ TMap<TString, TString> varyingLongNameMap;
+};
+
+//
+// This is the interface between the machine independent code
+// and the machine dependent code.
+//
+// The machine dependent code should derive from the classes
+// above. Then Construct*() and Delete*() will create and
+// destroy the machine dependent objects, which contain the
+// above machine independent information.
+//
+TCompiler* ConstructCompiler(
+ ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
+void DeleteCompiler(TCompiler*);
+
+#endif // _SHHANDLE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ShaderLang.cpp b/Source/ThirdParty/ANGLE/src/compiler/ShaderLang.cpp
new file mode 100644
index 000000000..ab8799c65
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ShaderLang.cpp
@@ -0,0 +1,262 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Implement the top-level of interface to the compiler,
+// as defined in ShaderLang.h
+//
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/InitializeDll.h"
+#include "compiler/ShHandle.h"
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler.
+//
+
+static int getVariableMaxLength(const TVariableInfoList& varList)
+{
+ TString::size_type maxLen = 0;
+ for (TVariableInfoList::const_iterator i = varList.begin();
+ i != varList.end(); ++i)
+ {
+ maxLen = std::max(maxLen, i->name.size());
+ }
+ // Add 1 to include null-termination character.
+ return static_cast<int>(maxLen) + 1;
+}
+
+static void getVariableInfo(ShShaderInfo varType,
+ const ShHandle handle,
+ int index,
+ int* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ if (!handle || !size || !type || !name)
+ return;
+ ASSERT((varType == SH_ACTIVE_ATTRIBUTES) ||
+ (varType == SH_ACTIVE_UNIFORMS));
+
+ TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return;
+
+ const TVariableInfoList& varList = varType == SH_ACTIVE_ATTRIBUTES ?
+ compiler->getAttribs() : compiler->getUniforms();
+ if (index < 0 || index >= static_cast<int>(varList.size()))
+ return;
+
+ const TVariableInfo& varInfo = varList[index];
+ if (length) *length = varInfo.name.size();
+ *size = varInfo.size;
+ *type = varInfo.type;
+ strcpy(name, varInfo.name.c_str());
+ if (mappedName)
+ strcpy(mappedName, varInfo.mappedName.c_str());
+}
+
+//
+// Driver must call this first, once, before doing any other
+// compiler operations.
+//
+int ShInitialize()
+{
+ if (!InitProcess())
+ return 0;
+
+ return 1;
+}
+
+//
+// Cleanup symbol tables
+//
+int ShFinalize()
+{
+ if (!DetachProcess())
+ return 0;
+
+ return 1;
+}
+
+//
+// Initialize built-in resources with minimum expected values.
+//
+void ShInitBuiltInResources(ShBuiltInResources* resources)
+{
+ // Constants.
+ resources->MaxVertexAttribs = 8;
+ resources->MaxVertexUniformVectors = 128;
+ resources->MaxVaryingVectors = 8;
+ resources->MaxVertexTextureImageUnits = 0;
+ resources->MaxCombinedTextureImageUnits = 8;
+ resources->MaxTextureImageUnits = 8;
+ resources->MaxFragmentUniformVectors = 16;
+ resources->MaxDrawBuffers = 1;
+
+ // Extensions.
+ resources->OES_standard_derivatives = 0;
+}
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
+ ShShaderOutput output,
+ const ShBuiltInResources* resources)
+{
+ if (!InitThread())
+ return 0;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return 0;
+
+ // Generate built-in symbol table.
+ if (!compiler->Init(*resources)) {
+ ShDestruct(base);
+ return 0;
+ }
+
+ return reinterpret_cast<void*>(base);
+}
+
+void ShDestruct(ShHandle handle)
+{
+ if (handle == 0)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+
+ if (base->getAsCompiler())
+ DeleteCompiler(base->getAsCompiler());
+}
+
+//
+// Do an actual compile on the given strings. The result is left
+// in the given compile object.
+//
+// Return: The return value of ShCompile is really boolean, indicating
+// success or failure.
+//
+int ShCompile(
+ const ShHandle handle,
+ const char* const shaderStrings[],
+ const int numStrings,
+ int compileOptions)
+{
+ if (!InitThread())
+ return 0;
+
+ if (handle == 0)
+ return 0;
+
+ TShHandleBase* base = reinterpret_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (compiler == 0)
+ return 0;
+
+ bool success = compiler->compile(shaderStrings, numStrings, compileOptions);
+ return success ? 1 : 0;
+}
+
+void ShGetInfo(const ShHandle handle, ShShaderInfo pname, int* params)
+{
+ if (!handle || !params)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ switch(pname)
+ {
+ case SH_INFO_LOG_LENGTH:
+ *params = compiler->getInfoSink().info.size() + 1;
+ break;
+ case SH_OBJECT_CODE_LENGTH:
+ *params = compiler->getInfoSink().obj.size() + 1;
+ break;
+ case SH_ACTIVE_UNIFORMS:
+ *params = compiler->getUniforms().size();
+ break;
+ case SH_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = getVariableMaxLength(compiler->getUniforms());
+ break;
+ case SH_ACTIVE_ATTRIBUTES:
+ *params = compiler->getAttribs().size();
+ break;
+ case SH_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = getVariableMaxLength(compiler->getAttribs());
+ break;
+ case SH_MAPPED_NAME_MAX_LENGTH:
+ *params = compiler->getMappedNameMaxLength();
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+//
+// Return any compiler log of messages for the application.
+//
+void ShGetInfoLog(const ShHandle handle, char* infoLog)
+{
+ if (!handle || !infoLog)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ TInfoSink& infoSink = compiler->getInfoSink();
+ strcpy(infoLog, infoSink.info.c_str());
+}
+
+//
+// Return any object code.
+//
+void ShGetObjectCode(const ShHandle handle, char* objCode)
+{
+ if (!handle || !objCode)
+ return;
+
+ TShHandleBase* base = static_cast<TShHandleBase*>(handle);
+ TCompiler* compiler = base->getAsCompiler();
+ if (!compiler) return;
+
+ TInfoSink& infoSink = compiler->getInfoSink();
+ strcpy(objCode, infoSink.obj.c_str());
+}
+
+void ShGetActiveAttrib(const ShHandle handle,
+ int index,
+ int* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ getVariableInfo(SH_ACTIVE_ATTRIBUTES,
+ handle, index, length, size, type, name, mappedName);
+}
+
+void ShGetActiveUniform(const ShHandle handle,
+ int index,
+ int* length,
+ int* size,
+ ShDataType* type,
+ char* name,
+ char* mappedName)
+{
+ getVariableInfo(SH_ACTIVE_UNIFORMS,
+ handle, index, length, size, type, name, mappedName);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.cpp b/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.cpp
new file mode 100644
index 000000000..02817d447
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.cpp
@@ -0,0 +1,232 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Symbol table for parsing. Most functionaliy and main ideas
+// are documented in the header file.
+//
+
+#include "compiler/SymbolTable.h"
+
+#include <stdio.h>
+
+//
+// TType helper function needs a place to live.
+//
+
+//
+// Recursively generate mangled names.
+//
+void TType::buildMangledName(TString& mangledName)
+{
+ if (isMatrix())
+ mangledName += 'm';
+ else if (isVector())
+ mangledName += 'v';
+
+ switch (type) {
+ case EbtFloat: mangledName += 'f'; break;
+ case EbtInt: mangledName += 'i'; break;
+ case EbtBool: mangledName += 'b'; break;
+ case EbtSampler2D: mangledName += "s2"; break;
+ case EbtSamplerCube: mangledName += "sC"; break;
+ case EbtStruct:
+ mangledName += "struct-";
+ if (typeName)
+ mangledName += *typeName;
+ {// support MSVC++6.0
+ for (unsigned int i = 0; i < structure->size(); ++i) {
+ mangledName += '-';
+ (*structure)[i].type->buildMangledName(mangledName);
+ }
+ }
+ default:
+ break;
+ }
+
+ mangledName += static_cast<char>('0' + getNominalSize());
+ if (isArray()) {
+ char buf[20];
+ sprintf(buf, "%d", arraySize);
+ mangledName += '[';
+ mangledName += buf;
+ mangledName += ']';
+ }
+}
+
+int TType::getStructSize() const
+{
+ if (!getStruct()) {
+ assert(false && "Not a struct");
+ return 0;
+ }
+
+ if (structureSize == 0)
+ for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++)
+ structureSize += ((*tl).type)->getObjectSize();
+
+ return structureSize;
+}
+
+//
+// Dump functions.
+//
+
+void TVariable::dump(TInfoSink& infoSink) const
+{
+ infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getPrecisionString() << " " << type.getBasicString();
+ if (type.isArray()) {
+ infoSink.debug << "[0]";
+ }
+ infoSink.debug << "\n";
+}
+
+void TFunction::dump(TInfoSink &infoSink) const
+{
+ infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n";
+}
+
+void TSymbolTableLevel::dump(TInfoSink &infoSink) const
+{
+ tLevel::const_iterator it;
+ for (it = level.begin(); it != level.end(); ++it)
+ (*it).second->dump(infoSink);
+}
+
+void TSymbolTable::dump(TInfoSink &infoSink) const
+{
+ for (int level = currentLevel(); level >= 0; --level) {
+ infoSink.debug << "LEVEL " << level << "\n";
+ table[level]->dump(infoSink);
+ }
+}
+
+//
+// Functions have buried pointers to delete.
+//
+TFunction::~TFunction()
+{
+ for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i)
+ delete (*i).type;
+}
+
+//
+// Symbol table levels are a map of pointers to symbols that have to be deleted.
+//
+TSymbolTableLevel::~TSymbolTableLevel()
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it)
+ delete (*it).second;
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in operation. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToOperator(const char* name, TOperator op)
+{
+ tLevel::iterator it;
+ for (it = level.begin(); it != level.end(); ++it) {
+ if ((*it).second->isFunction()) {
+ TFunction* function = static_cast<TFunction*>((*it).second);
+ if (function->getName() == name)
+ function->relateToOperator(op);
+ }
+ }
+}
+
+//
+// Change all function entries in the table with the non-mangled name
+// to be related to the provided built-in extension. This is a low
+// performance operation, and only intended for symbol tables that
+// live across a large number of compiles.
+//
+void TSymbolTableLevel::relateToExtension(const char* name, const TString& ext)
+{
+ for (tLevel::iterator it = level.begin(); it != level.end(); ++it) {
+ if (it->second->isFunction()) {
+ TFunction* function = static_cast<TFunction*>(it->second);
+ if (function->getName() == name)
+ function->relateToExtension(ext);
+ }
+ }
+}
+
+TSymbol::TSymbol(const TSymbol& copyOf)
+{
+ name = NewPoolTString(copyOf.name->c_str());
+ uniqueId = copyOf.uniqueId;
+}
+
+TVariable::TVariable(const TVariable& copyOf, TStructureMap& remapper) : TSymbol(copyOf)
+{
+ type.copyType(copyOf.type, remapper);
+ userType = copyOf.userType;
+ // for builtIn symbol table level, unionArray and arrayInformation pointers should be NULL
+ assert(copyOf.arrayInformationType == 0);
+ arrayInformationType = 0;
+
+ if (copyOf.unionArray) {
+ assert(!copyOf.type.getStruct());
+ assert(copyOf.type.getObjectSize() == 1);
+ unionArray = new ConstantUnion[1];
+ unionArray[0] = copyOf.unionArray[0];
+ } else
+ unionArray = 0;
+}
+
+TVariable* TVariable::clone(TStructureMap& remapper)
+{
+ TVariable *variable = new TVariable(*this, remapper);
+
+ return variable;
+}
+
+TFunction::TFunction(const TFunction& copyOf, TStructureMap& remapper) : TSymbol(copyOf)
+{
+ for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) {
+ TParameter param;
+ parameters.push_back(param);
+ parameters.back().copyParam(copyOf.parameters[i], remapper);
+ }
+
+ returnType.copyType(copyOf.returnType, remapper);
+ mangledName = copyOf.mangledName;
+ op = copyOf.op;
+ defined = copyOf.defined;
+}
+
+TFunction* TFunction::clone(TStructureMap& remapper)
+{
+ TFunction *function = new TFunction(*this, remapper);
+
+ return function;
+}
+
+TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper)
+{
+ TSymbolTableLevel *symTableLevel = new TSymbolTableLevel();
+ tLevel::iterator iter;
+ for (iter = level.begin(); iter != level.end(); ++iter) {
+ symTableLevel->insert(*iter->second->clone(remapper));
+ }
+
+ return symTableLevel;
+}
+
+void TSymbolTable::copyTable(const TSymbolTable& copyOf)
+{
+ TStructureMap remapper;
+ uniqueId = copyOf.uniqueId;
+ for (unsigned int i = 0; i < copyOf.table.size(); ++i) {
+ table.push_back(copyOf.table[i]->clone(remapper));
+ }
+ for( unsigned int i = 0; i < copyOf.precisionStack.size(); i++) {
+ precisionStack.push_back( copyOf.precisionStack[i] );
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.h b/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.h
new file mode 100644
index 000000000..38bc65759
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/SymbolTable.h
@@ -0,0 +1,348 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _SYMBOL_TABLE_INCLUDED_
+#define _SYMBOL_TABLE_INCLUDED_
+
+//
+// Symbol table for parsing. Has these design characteristics:
+//
+// * Same symbol table can be used to compile many shaders, to preserve
+// effort of creating and loading with the large numbers of built-in
+// symbols.
+//
+// * Name mangling will be used to give each function a unique name
+// so that symbol table lookups are never ambiguous. This allows
+// a simpler symbol table structure.
+//
+// * Pushing and popping of scope, so symbol table will really be a stack
+// of symbol tables. Searched from the top, with new inserts going into
+// the top.
+//
+// * Constants: Compile time constant symbols will keep their values
+// in the symbol table. The parser can substitute constants at parse
+// time, including doing constant folding and constant propagation.
+//
+// * No temporaries: Temporaries made from operations (+, --, .xy, etc.)
+// are tracked in the intermediate representation, not the symbol table.
+//
+
+#include <assert.h>
+
+#include "compiler/InfoSink.h"
+#include "compiler/intermediate.h"
+
+//
+// Symbol base class. (Can build functions or variables out of these...)
+//
+class TSymbol {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+ TSymbol(const TString *n) : name(n) { }
+ virtual ~TSymbol() { /* don't delete name, it's from the pool */ }
+ const TString& getName() const { return *name; }
+ virtual const TString& getMangledName() const { return getName(); }
+ virtual bool isFunction() const { return false; }
+ virtual bool isVariable() const { return false; }
+ void setUniqueId(int id) { uniqueId = id; }
+ int getUniqueId() const { return uniqueId; }
+ virtual void dump(TInfoSink &infoSink) const = 0;
+ TSymbol(const TSymbol&);
+ virtual TSymbol* clone(TStructureMap& remapper) = 0;
+
+protected:
+ const TString *name;
+ unsigned int uniqueId; // For real comparing during code generation
+};
+
+//
+// Variable class, meaning a symbol that's not a function.
+//
+// There could be a separate class heirarchy for Constant variables;
+// Only one of int, bool, or float, (or none) is correct for
+// any particular use, but it's easy to do this way, and doesn't
+// seem worth having separate classes, and "getConst" can't simply return
+// different values for different types polymorphically, so this is
+// just simple and pragmatic.
+//
+class TVariable : public TSymbol {
+public:
+ TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { }
+ virtual ~TVariable() { }
+ virtual bool isVariable() const { return true; }
+ TType& getType() { return type; }
+ const TType& getType() const { return type; }
+ bool isUserType() const { return userType; }
+ void setQualifier(TQualifier qualifier) { type.setQualifier(qualifier); }
+ void updateArrayInformationType(TType *t) { arrayInformationType = t; }
+ TType* getArrayInformationType() { return arrayInformationType; }
+
+ virtual void dump(TInfoSink &infoSink) const;
+
+ ConstantUnion* getConstPointer()
+ {
+ if (!unionArray)
+ unionArray = new ConstantUnion[type.getObjectSize()];
+
+ return unionArray;
+ }
+
+ ConstantUnion* getConstPointer() const { return unionArray; }
+
+ void shareConstPointer( ConstantUnion *constArray)
+ {
+ if (unionArray == constArray)
+ return;
+
+ delete[] unionArray;
+ unionArray = constArray;
+ }
+ TVariable(const TVariable&, TStructureMap& remapper); // copy constructor
+ virtual TVariable* clone(TStructureMap& remapper);
+
+protected:
+ TType type;
+ bool userType;
+ // we are assuming that Pool Allocator will free the memory allocated to unionArray
+ // when this object is destroyed
+ ConstantUnion *unionArray;
+ TType *arrayInformationType; // this is used for updating maxArraySize in all the references to a given symbol
+};
+
+//
+// The function sub-class of symbols and the parser will need to
+// share this definition of a function parameter.
+//
+struct TParameter {
+ TString *name;
+ TType* type;
+ void copyParam(const TParameter& param, TStructureMap& remapper)
+ {
+ name = NewPoolTString(param.name->c_str());
+ type = param.type->clone(remapper);
+ }
+};
+
+//
+// The function sub-class of a symbol.
+//
+class TFunction : public TSymbol {
+public:
+ TFunction(TOperator o) :
+ TSymbol(0),
+ returnType(TType(EbtVoid, EbpUndefined)),
+ op(o),
+ defined(false) { }
+ TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) :
+ TSymbol(name),
+ returnType(retType),
+ mangledName(TFunction::mangleName(*name)),
+ op(tOp),
+ defined(false) { }
+ virtual ~TFunction();
+ virtual bool isFunction() const { return true; }
+
+ static TString mangleName(const TString& name) { return name + '('; }
+ static TString unmangleName(const TString& mangledName)
+ {
+ return TString(mangledName.c_str(), mangledName.find_first_of('('));
+ }
+
+ void addParameter(TParameter& p)
+ {
+ parameters.push_back(p);
+ mangledName = mangledName + p.type->getMangledName();
+ }
+
+ const TString& getMangledName() const { return mangledName; }
+ const TType& getReturnType() const { return returnType; }
+
+ void relateToOperator(TOperator o) { op = o; }
+ TOperator getBuiltInOp() const { return op; }
+
+ void relateToExtension(const TString& ext) { extension = ext; }
+ const TString& getExtension() const { return extension; }
+
+ void setDefined() { defined = true; }
+ bool isDefined() { return defined; }
+
+ int getParamCount() const { return static_cast<int>(parameters.size()); }
+ const TParameter& getParam(int i) const { return parameters[i]; }
+
+ virtual void dump(TInfoSink &infoSink) const;
+ TFunction(const TFunction&, TStructureMap& remapper);
+ virtual TFunction* clone(TStructureMap& remapper);
+
+protected:
+ typedef TVector<TParameter> TParamList;
+ TParamList parameters;
+ TType returnType;
+ TString mangledName;
+ TOperator op;
+ TString extension;
+ bool defined;
+};
+
+
+class TSymbolTableLevel {
+public:
+ typedef TMap<TString, TSymbol*> tLevel;
+ typedef tLevel::const_iterator const_iterator;
+ typedef const tLevel::value_type tLevelPair;
+ typedef std::pair<tLevel::iterator, bool> tInsertResult;
+
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+ TSymbolTableLevel() { }
+ ~TSymbolTableLevel();
+
+ bool insert(TSymbol& symbol)
+ {
+ //
+ // returning true means symbol was added to the table
+ //
+ tInsertResult result;
+ result = level.insert(tLevelPair(symbol.getMangledName(), &symbol));
+
+ return result.second;
+ }
+
+ TSymbol* find(const TString& name) const
+ {
+ tLevel::const_iterator it = level.find(name);
+ if (it == level.end())
+ return 0;
+ else
+ return (*it).second;
+ }
+
+ const_iterator begin() const
+ {
+ return level.begin();
+ }
+
+ const_iterator end() const
+ {
+ return level.end();
+ }
+
+ void relateToOperator(const char* name, TOperator op);
+ void relateToExtension(const char* name, const TString& ext);
+ void dump(TInfoSink &infoSink) const;
+ TSymbolTableLevel* clone(TStructureMap& remapper);
+
+protected:
+ tLevel level;
+};
+
+class TSymbolTable {
+public:
+ TSymbolTable() : uniqueId(0)
+ {
+ //
+ // The symbol table cannot be used until push() is called, but
+ // the lack of an initial call to push() can be used to detect
+ // that the symbol table has not been preloaded with built-ins.
+ //
+ }
+
+ ~TSymbolTable()
+ {
+ // level 0 is always built In symbols, so we never pop that out
+ while (table.size() > 1)
+ pop();
+ }
+
+ //
+ // When the symbol table is initialized with the built-ins, there should
+ // 'push' calls, so that built-ins are at level 0 and the shader
+ // globals are at level 1.
+ //
+ bool isEmpty() { return table.size() == 0; }
+ bool atBuiltInLevel() { return table.size() == 1; }
+ bool atGlobalLevel() { return table.size() <= 2; }
+ void push()
+ {
+ table.push_back(new TSymbolTableLevel);
+ precisionStack.push_back( PrecisionStackLevel() );
+ }
+
+ void pop()
+ {
+ delete table[currentLevel()];
+ table.pop_back();
+ precisionStack.pop_back();
+ }
+
+ bool insert(TSymbol& symbol)
+ {
+ symbol.setUniqueId(++uniqueId);
+ return table[currentLevel()]->insert(symbol);
+ }
+
+ TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0)
+ {
+ int level = currentLevel();
+ TSymbol* symbol;
+ do {
+ symbol = table[level]->find(name);
+ --level;
+ } while (symbol == 0 && level >= 0);
+ level++;
+ if (builtIn)
+ *builtIn = level == 0;
+ if (sameScope)
+ *sameScope = level == currentLevel();
+ return symbol;
+ }
+
+ TSymbolTableLevel* getGlobalLevel() {
+ assert(table.size() >= 2);
+ return table[1];
+ }
+ void relateToOperator(const char* name, TOperator op) {
+ table[0]->relateToOperator(name, op);
+ }
+ void relateToExtension(const char* name, const TString& ext) {
+ table[0]->relateToExtension(name, ext);
+ }
+ int getMaxSymbolId() { return uniqueId; }
+ void dump(TInfoSink &infoSink) const;
+ void copyTable(const TSymbolTable& copyOf);
+
+ void setDefaultPrecision( TBasicType type, TPrecision prec ){
+ if( type != EbtFloat && type != EbtInt ) return; // Only set default precision for int/float
+ int indexOfLastElement = static_cast<int>(precisionStack.size()) - 1;
+ precisionStack[indexOfLastElement][type] = prec; // Uses map operator [], overwrites the current value
+ }
+
+ // Searches down the precisionStack for a precision qualifier for the specified TBasicType
+ TPrecision getDefaultPrecision( TBasicType type){
+ if( type != EbtFloat && type != EbtInt ) return EbpUndefined;
+ int level = static_cast<int>(precisionStack.size()) - 1;
+ assert( level >= 0); // Just to be safe. Should not happen.
+ PrecisionStackLevel::iterator it;
+ TPrecision prec = EbpUndefined; // If we dont find anything we return this. Should we error check this?
+ while( level >= 0 ){
+ it = precisionStack[level].find( type );
+ if( it != precisionStack[level].end() ){
+ prec = (*it).second;
+ break;
+ }
+ level--;
+ }
+ return prec;
+ }
+
+protected:
+ int currentLevel() const { return static_cast<int>(table.size()) - 1; }
+
+ std::vector<TSymbolTableLevel*> table;
+ typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
+ std::vector< PrecisionStackLevel > precisionStack;
+ int uniqueId; // for unique identification in code generation
+};
+
+#endif // _SYMBOL_TABLE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.cpp
new file mode 100644
index 000000000..bb201a48c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.cpp
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorESSL.h"
+
+#include "compiler/OutputESSL.h"
+
+TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec) {
+}
+
+void TranslatorESSL::translate(TIntermNode* root) {
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write built-in extension behaviors.
+ writeExtensionBehavior();
+
+ // Write translated shader.
+ TOutputESSL outputESSL(sink);
+ root->traverse(&outputESSL);
+}
+
+void TranslatorESSL::writeExtensionBehavior() {
+ TInfoSinkBase& sink = getInfoSink().obj;
+ const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
+ for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
+ iter != extensionBehavior.end(); ++iter) {
+ sink << "#extension " << iter->first << " : "
+ << getBehaviorString(iter->second) << "\n";
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.h b/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.h
new file mode 100644
index 000000000..a1196bd00
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/TranslatorESSL.h
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORESSL_H_
+#define COMPILER_TRANSLATORESSL_H_
+
+#include "compiler/ShHandle.h"
+
+class TranslatorESSL : public TCompiler {
+public:
+ TranslatorESSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+
+private:
+ void writeExtensionBehavior();
+};
+
+#endif // COMPILER_TRANSLATORESSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.cpp
new file mode 100644
index 000000000..7a63ae1f0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.cpp
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorGLSL.h"
+
+#include "compiler/OutputGLSL.h"
+#include "compiler/VersionGLSL.h"
+
+static void writeVersion(ShShaderType type, TIntermNode* root,
+ TInfoSinkBase& sink) {
+ TVersionGLSL versionGLSL(type);
+ root->traverse(&versionGLSL);
+ int version = versionGLSL.getVersion();
+ // We need to write version directive only if it is greater than 110.
+ // If there is no version directive in the shader, 110 is implied.
+ if (version > 110) {
+ sink << "#version " << version << "\n";
+ }
+}
+
+TranslatorGLSL::TranslatorGLSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec) {
+}
+
+void TranslatorGLSL::translate(TIntermNode* root) {
+ TInfoSinkBase& sink = getInfoSink().obj;
+
+ // Write GLSL version.
+ writeVersion(getShaderType(), root, sink);
+
+ // Write translated shader.
+ TOutputGLSL outputGLSL(sink);
+ root->traverse(&outputGLSL);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.h
new file mode 100644
index 000000000..c2ce06d19
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/TranslatorGLSL.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORGLSL_H_
+#define COMPILER_TRANSLATORGLSL_H_
+
+#include "compiler/ShHandle.h"
+
+class TranslatorGLSL : public TCompiler {
+public:
+ TranslatorGLSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+};
+
+#endif // COMPILER_TRANSLATORGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.cpp
new file mode 100644
index 000000000..96d7f1077
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.cpp
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/TranslatorHLSL.h"
+
+#include "compiler/OutputHLSL.h"
+
+TranslatorHLSL::TranslatorHLSL(ShShaderType type, ShShaderSpec spec)
+ : TCompiler(type, spec)
+{
+}
+
+void TranslatorHLSL::translate(TIntermNode *root)
+{
+ TParseContext& parseContext = *GetGlobalParseContext();
+ sh::OutputHLSL outputHLSL(parseContext);
+
+ outputHLSL.output();
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.h b/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.h
new file mode 100644
index 000000000..c3f672ba9
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/TranslatorHLSL.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_TRANSLATORHLSL_H_
+#define COMPILER_TRANSLATORHLSL_H_
+
+#include "compiler/ShHandle.h"
+
+class TranslatorHLSL : public TCompiler {
+public:
+ TranslatorHLSL(ShShaderType type, ShShaderSpec spec);
+
+protected:
+ virtual void translate(TIntermNode* root);
+};
+
+#endif // COMPILER_TRANSLATORHLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/Types.h b/Source/ThirdParty/ANGLE/src/compiler/Types.h
new file mode 100644
index 000000000..d0fcc08b9
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/Types.h
@@ -0,0 +1,293 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _TYPES_INCLUDED
+#define _TYPES_INCLUDED
+
+#include "compiler/BaseTypes.h"
+#include "compiler/Common.h"
+#include "compiler/debug.h"
+
+//
+// Need to have association of line numbers to types in a list for building structs.
+//
+class TType;
+struct TTypeLine {
+ TType* type;
+ int line;
+};
+typedef TVector<TTypeLine> TTypeList;
+
+inline TTypeList* NewPoolTTypeList()
+{
+ void* memory = GlobalPoolAllocator.allocate(sizeof(TTypeList));
+ return new(memory) TTypeList;
+}
+
+//
+// This is a workaround for a problem with the yacc stack, It can't have
+// types that it thinks have non-trivial constructors. It should
+// just be used while recognizing the grammar, not anything else. Pointers
+// could be used, but also trying to avoid lots of memory management overhead.
+//
+// Not as bad as it looks, there is no actual assumption that the fields
+// match up or are name the same or anything like that.
+//
+class TPublicType {
+public:
+ TBasicType type;
+ TQualifier qualifier;
+ TPrecision precision;
+ int size; // size of vector or matrix, not size of array
+ bool matrix;
+ bool array;
+ int arraySize;
+ TType* userDef;
+ int line;
+
+ void setBasic(TBasicType bt, TQualifier q, int ln = 0)
+ {
+ type = bt;
+ qualifier = q;
+ precision = EbpUndefined;
+ size = 1;
+ matrix = false;
+ array = false;
+ arraySize = 0;
+ userDef = 0;
+ line = ln;
+ }
+
+ void setAggregate(int s, bool m = false)
+ {
+ size = s;
+ matrix = m;
+ }
+
+ void setArray(bool a, int s = 0)
+ {
+ array = a;
+ arraySize = s;
+ }
+};
+
+typedef TMap<TTypeList*, TTypeList*> TStructureMap;
+typedef TMap<TTypeList*, TTypeList*>::iterator TStructureMapIterator;
+//
+// Base class for things that have a type.
+//
+class TType {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+ TType() {}
+ TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false) :
+ type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0),
+ maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), fieldName(0), mangled(0), typeName(0)
+ {
+ }
+ explicit TType(const TPublicType &p) :
+ type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize),
+ maxArraySize(0), arrayInformationType(0), structure(0), structureSize(0), fieldName(0), mangled(0), typeName(0)
+ {
+ if (p.userDef) {
+ structure = p.userDef->getStruct();
+ typeName = NewPoolTString(p.userDef->getTypeName().c_str());
+ }
+ }
+ TType(TTypeList* userDef, const TString& n, TPrecision p = EbpUndefined) :
+ type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0),
+ maxArraySize(0), arrayInformationType(0), structure(userDef), structureSize(0), fieldName(0), mangled(0)
+ {
+ typeName = NewPoolTString(n.c_str());
+ }
+
+ void copyType(const TType& copyOf, TStructureMap& remapper)
+ {
+ type = copyOf.type;
+ precision = copyOf.precision;
+ qualifier = copyOf.qualifier;
+ size = copyOf.size;
+ matrix = copyOf.matrix;
+ array = copyOf.array;
+ arraySize = copyOf.arraySize;
+
+ TStructureMapIterator iter;
+ if (copyOf.structure) {
+ if ((iter = remapper.find(structure)) == remapper.end()) {
+ // create the new structure here
+ structure = NewPoolTTypeList();
+ for (unsigned int i = 0; i < copyOf.structure->size(); ++i) {
+ TTypeLine typeLine;
+ typeLine.line = (*copyOf.structure)[i].line;
+ typeLine.type = (*copyOf.structure)[i].type->clone(remapper);
+ structure->push_back(typeLine);
+ }
+ } else {
+ structure = iter->second;
+ }
+ } else
+ structure = 0;
+
+ fieldName = 0;
+ if (copyOf.fieldName)
+ fieldName = NewPoolTString(copyOf.fieldName->c_str());
+ typeName = 0;
+ if (copyOf.typeName)
+ typeName = NewPoolTString(copyOf.typeName->c_str());
+
+ mangled = 0;
+ if (copyOf.mangled)
+ mangled = NewPoolTString(copyOf.mangled->c_str());
+
+ structureSize = copyOf.structureSize;
+ maxArraySize = copyOf.maxArraySize;
+ assert(copyOf.arrayInformationType == 0);
+ arrayInformationType = 0; // arrayInformationType should not be set for builtIn symbol table level
+ }
+
+ TType* clone(TStructureMap& remapper)
+ {
+ TType *newType = new TType();
+ newType->copyType(*this, remapper);
+
+ return newType;
+ }
+
+ TBasicType getBasicType() const { return type; }
+ void setBasicType(TBasicType t) { type = t; }
+
+ TPrecision getPrecision() const { return precision; }
+ void setPrecision(TPrecision p) { precision = p; }
+
+ TQualifier getQualifier() const { return qualifier; }
+ void setQualifier(TQualifier q) { qualifier = q; }
+
+ // One-dimensional size of single instance type
+ int getNominalSize() const { return size; }
+ void setNominalSize(int s) { size = s; }
+ // Full size of single instance of type
+ int getObjectSize() const
+ {
+ int totalSize;
+
+ if (getBasicType() == EbtStruct)
+ totalSize = getStructSize();
+ else if (matrix)
+ totalSize = size * size;
+ else
+ totalSize = size;
+
+ if (isArray())
+ totalSize *= std::max(getArraySize(), getMaxArraySize());
+
+ return totalSize;
+ }
+
+ bool isMatrix() const { return matrix ? true : false; }
+ void setMatrix(bool m) { matrix = m; }
+
+ bool isArray() const { return array ? true : false; }
+ int getArraySize() const { return arraySize; }
+ void setArraySize(int s) { array = true; arraySize = s; }
+ int getMaxArraySize () const { return maxArraySize; }
+ void setMaxArraySize (int s) { maxArraySize = s; }
+ void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; }
+ void setArrayInformationType(TType* t) { arrayInformationType = t; }
+ TType* getArrayInformationType() const { return arrayInformationType; }
+
+ bool isVector() const { return size > 1 && !matrix; }
+ bool isScalar() const { return size == 1 && !matrix && !structure; }
+
+ TTypeList* getStruct() const { return structure; }
+ void setStruct(TTypeList* s) { structure = s; }
+
+ const TString& getTypeName() const
+ {
+ assert(typeName);
+ return *typeName;
+ }
+ void setTypeName(const TString& n)
+ {
+ typeName = NewPoolTString(n.c_str());
+ }
+
+ bool isField() const { return fieldName != 0; }
+ const TString& getFieldName() const
+ {
+ assert(fieldName);
+ return *fieldName;
+ }
+ void setFieldName(const TString& n)
+ {
+ fieldName = NewPoolTString(n.c_str());
+ }
+
+ TString& getMangledName() {
+ if (!mangled) {
+ mangled = NewPoolTString("");
+ buildMangledName(*mangled);
+ *mangled += ';' ;
+ }
+
+ return *mangled;
+ }
+
+ bool sameElementType(const TType& right) const {
+ return type == right.type &&
+ size == right.size &&
+ matrix == right.matrix &&
+ structure == right.structure;
+ }
+ bool operator==(const TType& right) const {
+ return type == right.type &&
+ size == right.size &&
+ matrix == right.matrix &&
+ array == right.array && (!array || arraySize == right.arraySize) &&
+ structure == right.structure;
+ // don't check the qualifier, it's not ever what's being sought after
+ }
+ bool operator!=(const TType& right) const {
+ return !operator==(right);
+ }
+ bool operator<(const TType& right) const {
+ if (type != right.type) return type < right.type;
+ if (size != right.size) return size < right.size;
+ if (matrix != right.matrix) return matrix < right.matrix;
+ if (array != right.array) return array < right.array;
+ if (arraySize != right.arraySize) return arraySize < right.arraySize;
+ if (structure != right.structure) return structure < right.structure;
+
+ return false;
+ }
+
+ const char* getBasicString() const { return ::getBasicString(type); }
+ const char* getPrecisionString() const { return ::getPrecisionString(precision); }
+ const char* getQualifierString() const { return ::getQualifierString(qualifier); }
+ TString getCompleteString() const;
+
+protected:
+ void buildMangledName(TString&);
+ int getStructSize() const;
+
+ TBasicType type : 6;
+ TPrecision precision;
+ TQualifier qualifier : 7;
+ int size : 8; // size of vector or matrix, not size of array
+ unsigned int matrix : 1;
+ unsigned int array : 1;
+ int arraySize;
+ int maxArraySize;
+ TType* arrayInformationType;
+
+ TTypeList* structure; // 0 unless this is a struct
+ mutable int structureSize;
+
+ TString *fieldName; // for structure field names
+ TString *mangled;
+ TString *typeName; // for structure field type name
+};
+
+#endif // _TYPES_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/UnfoldSelect.cpp b/Source/ThirdParty/ANGLE/src/compiler/UnfoldSelect.cpp
new file mode 100644
index 000000000..a36c3931e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/UnfoldSelect.cpp
@@ -0,0 +1,65 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldSelect is an AST traverser to output the select operator ?: as if-else statements
+//
+
+#include "compiler/UnfoldSelect.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/OutputHLSL.h"
+
+namespace sh
+{
+UnfoldSelect::UnfoldSelect(TParseContext &context, OutputHLSL *outputHLSL) : mContext(context), mOutputHLSL(outputHLSL)
+{
+ mTemporaryIndex = 0;
+}
+
+void UnfoldSelect::traverse(TIntermNode *node)
+{
+ mTemporaryIndex++;
+ node->traverse(this);
+}
+
+bool UnfoldSelect::visitSelection(Visit visit, TIntermSelection *node)
+{
+ TInfoSinkBase &out = mOutputHLSL->getBodyStream();
+
+ if (node->usesTernaryOperator())
+ {
+ int i = mTemporaryIndex++;
+
+ out << mOutputHLSL->typeString(node->getType()) << " t" << i << ";\n";
+
+ node->getCondition()->traverse(this);
+ out << "if(";
+ node->getCondition()->traverse(mOutputHLSL);
+ out << ")\n"
+ "{\n";
+ node->getTrueBlock()->traverse(this);
+ out << " t" << i << " = ";
+ node->getTrueBlock()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n"
+ "else\n"
+ "{\n";
+ node->getFalseBlock()->traverse(this);
+ out << " t" << i << " = ";
+ node->getFalseBlock()->traverse(mOutputHLSL);
+ out << ";\n"
+ "}\n";
+
+ mTemporaryIndex--;
+ }
+
+ return false;
+}
+
+int UnfoldSelect::getTemporaryIndex()
+{
+ return mTemporaryIndex;
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/UnfoldSelect.h b/Source/ThirdParty/ANGLE/src/compiler/UnfoldSelect.h
new file mode 100644
index 000000000..de296e442
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/UnfoldSelect.h
@@ -0,0 +1,37 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// UnfoldSelect is an AST traverser to output the select operator ?: as if-else statements
+//
+
+#ifndef COMPILER_UNFOLDSELECT_H_
+#define COMPILER_UNFOLDSELECT_H_
+
+#include "compiler/intermediate.h"
+#include "compiler/ParseHelper.h"
+
+namespace sh
+{
+class OutputHLSL;
+
+class UnfoldSelect : public TIntermTraverser
+{
+ public:
+ UnfoldSelect(TParseContext &context, OutputHLSL *outputHLSL);
+
+ void traverse(TIntermNode *node);
+ bool visitSelection(Visit visit, TIntermSelection *node);
+
+ int getTemporaryIndex();
+
+ protected:
+ TParseContext &mContext;
+ OutputHLSL *const mOutputHLSL;
+
+ int mTemporaryIndex;
+};
+}
+
+#endif // COMPILER_UNFOLDSELECT_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.cpp b/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.cpp
new file mode 100644
index 000000000..b46e4b91b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.cpp
@@ -0,0 +1,543 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/ValidateLimitations.h"
+#include "compiler/InfoSink.h"
+#include "compiler/ParseHelper.h"
+
+namespace {
+bool IsLoopIndex(const TIntermSymbol* symbol, const TLoopStack& stack) {
+ for (TLoopStack::const_iterator i = stack.begin(); i != stack.end(); ++i) {
+ if (i->index.id == symbol->getId())
+ return true;
+ }
+ return false;
+}
+
+void MarkLoopForUnroll(const TIntermSymbol* symbol, TLoopStack& stack) {
+ for (TLoopStack::iterator i = stack.begin(); i != stack.end(); ++i) {
+ if (i->index.id == symbol->getId()) {
+ ASSERT(i->loop != NULL);
+ i->loop->setUnrollFlag(true);
+ return;
+ }
+ }
+ UNREACHABLE();
+}
+
+// Traverses a node to check if it represents a constant index expression.
+// Definition:
+// constant-index-expressions are a superset of constant-expressions.
+// Constant-index-expressions can include loop indices as defined in
+// GLSL ES 1.0 spec, Appendix A, section 4.
+// The following are constant-index-expressions:
+// - Constant expressions
+// - Loop indices as defined in section 4
+// - Expressions composed of both of the above
+class ValidateConstIndexExpr : public TIntermTraverser {
+public:
+ ValidateConstIndexExpr(const TLoopStack& stack)
+ : mValid(true), mLoopStack(stack) {}
+
+ // Returns true if the parsed node represents a constant index expression.
+ bool isValid() const { return mValid; }
+
+ virtual void visitSymbol(TIntermSymbol* symbol) {
+ // Only constants and loop indices are allowed in a
+ // constant index expression.
+ if (mValid) {
+ mValid = (symbol->getQualifier() == EvqConst) ||
+ IsLoopIndex(symbol, mLoopStack);
+ }
+ }
+ virtual void visitConstantUnion(TIntermConstantUnion*) {}
+ virtual bool visitBinary(Visit, TIntermBinary*) { return true; }
+ virtual bool visitUnary(Visit, TIntermUnary*) { return true; }
+ virtual bool visitSelection(Visit, TIntermSelection*) { return true; }
+ virtual bool visitAggregate(Visit, TIntermAggregate*) { return true; }
+ virtual bool visitLoop(Visit, TIntermLoop*) { return true; }
+ virtual bool visitBranch(Visit, TIntermBranch*) { return true; }
+
+private:
+ bool mValid;
+ const TLoopStack& mLoopStack;
+};
+
+// Traverses a node to check if it uses a loop index.
+// If an int loop index is used in its body as a sampler array index,
+// mark the loop for unroll.
+class ValidateLoopIndexExpr : public TIntermTraverser {
+public:
+ ValidateLoopIndexExpr(TLoopStack& stack)
+ : mUsesFloatLoopIndex(false),
+ mUsesIntLoopIndex(false),
+ mLoopStack(stack) {}
+
+ bool usesFloatLoopIndex() const { return mUsesFloatLoopIndex; }
+ bool usesIntLoopIndex() const { return mUsesIntLoopIndex; }
+
+ virtual void visitSymbol(TIntermSymbol* symbol) {
+ if (IsLoopIndex(symbol, mLoopStack)) {
+ switch (symbol->getBasicType()) {
+ case EbtFloat:
+ mUsesFloatLoopIndex = true;
+ break;
+ case EbtInt:
+ mUsesIntLoopIndex = true;
+ MarkLoopForUnroll(symbol, mLoopStack);
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ }
+ virtual void visitConstantUnion(TIntermConstantUnion*) {}
+ virtual bool visitBinary(Visit, TIntermBinary*) { return true; }
+ virtual bool visitUnary(Visit, TIntermUnary*) { return true; }
+ virtual bool visitSelection(Visit, TIntermSelection*) { return true; }
+ virtual bool visitAggregate(Visit, TIntermAggregate*) { return true; }
+ virtual bool visitLoop(Visit, TIntermLoop*) { return true; }
+ virtual bool visitBranch(Visit, TIntermBranch*) { return true; }
+
+private:
+ bool mUsesFloatLoopIndex;
+ bool mUsesIntLoopIndex;
+ TLoopStack& mLoopStack;
+};
+} // namespace
+
+ValidateLimitations::ValidateLimitations(ShShaderType shaderType,
+ TInfoSinkBase& sink)
+ : mShaderType(shaderType),
+ mSink(sink),
+ mNumErrors(0)
+{
+}
+
+void ValidateLimitations::visitSymbol(TIntermSymbol*)
+{
+}
+
+void ValidateLimitations::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool ValidateLimitations::visitBinary(Visit, TIntermBinary* node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getLeft());
+
+ // Check indexing.
+ switch (node->getOp()) {
+ case EOpIndexDirect:
+ validateIndexing(node);
+ break;
+ case EOpIndexIndirect:
+#if defined(__APPLE__)
+ // Loop unrolling is a work-around for a Mac Cg compiler bug where it
+ // crashes when a sampler array's index is also the loop index.
+ // Once Apple fixes this bug, we should remove the code in this CL.
+ // See http://codereview.appspot.com/4331048/.
+ if ((node->getLeft() != NULL) && (node->getRight() != NULL) &&
+ (node->getLeft()->getAsSymbolNode())) {
+ TIntermSymbol* symbol = node->getLeft()->getAsSymbolNode();
+ if (IsSampler(symbol->getBasicType()) && symbol->isArray()) {
+ ValidateLoopIndexExpr validate(mLoopStack);
+ node->getRight()->traverse(&validate);
+ if (validate.usesFloatLoopIndex()) {
+ error(node->getLine(),
+ "sampler array index is float loop index",
+ "for");
+ }
+ }
+ }
+#endif
+ validateIndexing(node);
+ break;
+ default: break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitUnary(Visit, TIntermUnary* node)
+{
+ // Check if loop index is modified in the loop body.
+ validateOperation(node, node->getOperand());
+
+ return true;
+}
+
+bool ValidateLimitations::visitSelection(Visit, TIntermSelection*)
+{
+ return true;
+}
+
+bool ValidateLimitations::visitAggregate(Visit, TIntermAggregate* node)
+{
+ switch (node->getOp()) {
+ case EOpFunctionCall:
+ validateFunctionCall(node);
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+bool ValidateLimitations::visitLoop(Visit, TIntermLoop* node)
+{
+ if (!validateLoopType(node))
+ return false;
+
+ TLoopInfo info;
+ memset(&info, 0, sizeof(TLoopInfo));
+ info.loop = node;
+ if (!validateForLoopHeader(node, &info))
+ return false;
+
+ TIntermNode* body = node->getBody();
+ if (body != NULL) {
+ mLoopStack.push_back(info);
+ body->traverse(this);
+ mLoopStack.pop_back();
+ }
+
+ // The loop is fully processed - no need to visit children.
+ return false;
+}
+
+bool ValidateLimitations::visitBranch(Visit, TIntermBranch*)
+{
+ return true;
+}
+
+void ValidateLimitations::error(TSourceLoc loc,
+ const char *reason, const char* token)
+{
+ mSink.prefix(EPrefixError);
+ mSink.location(loc);
+ mSink << "'" << token << "' : " << reason << "\n";
+ ++mNumErrors;
+}
+
+bool ValidateLimitations::withinLoopBody() const
+{
+ return !mLoopStack.empty();
+}
+
+bool ValidateLimitations::isLoopIndex(const TIntermSymbol* symbol) const
+{
+ return IsLoopIndex(symbol, mLoopStack);
+}
+
+bool ValidateLimitations::validateLoopType(TIntermLoop* node) {
+ TLoopType type = node->getType();
+ if (type == ELoopFor)
+ return true;
+
+ // Reject while and do-while loops.
+ error(node->getLine(),
+ "This type of loop is not allowed",
+ type == ELoopWhile ? "while" : "do");
+ return false;
+}
+
+bool ValidateLimitations::validateForLoopHeader(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ ASSERT(node->getType() == ELoopFor);
+
+ //
+ // The for statement has the form:
+ // for ( init-declaration ; condition ; expression ) statement
+ //
+ if (!validateForLoopInit(node, info))
+ return false;
+ if (!validateForLoopCond(node, info))
+ return false;
+ if (!validateForLoopExpr(node, info))
+ return false;
+
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopInit(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* init = node->getInit();
+ if (init == NULL) {
+ error(node->getLine(), "Missing init declaration", "for");
+ return false;
+ }
+
+ //
+ // init-declaration has the form:
+ // type-specifier identifier = constant-expression
+ //
+ TIntermAggregate* decl = init->getAsAggregate();
+ if ((decl == NULL) || (decl->getOp() != EOpDeclaration)) {
+ error(init->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ // To keep things simple do not allow declaration list.
+ TIntermSequence& declSeq = decl->getSequence();
+ if (declSeq.size() != 1) {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ TIntermBinary* declInit = declSeq[0]->getAsBinaryNode();
+ if ((declInit == NULL) || (declInit->getOp() != EOpInitialize)) {
+ error(decl->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ TIntermSymbol* symbol = declInit->getLeft()->getAsSymbolNode();
+ if (symbol == NULL) {
+ error(declInit->getLine(), "Invalid init declaration", "for");
+ return false;
+ }
+ // The loop index has type int or float.
+ TBasicType type = symbol->getBasicType();
+ if ((type != EbtInt) && (type != EbtFloat)) {
+ error(symbol->getLine(),
+ "Invalid type for loop index", getBasicString(type));
+ return false;
+ }
+ // The loop index is initialized with constant expression.
+ if (!isConstExpr(declInit->getRight())) {
+ error(declInit->getLine(),
+ "Loop index cannot be initialized with non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+
+ info->index.id = symbol->getId();
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopCond(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* cond = node->getCondition();
+ if (cond == NULL) {
+ error(node->getLine(), "Missing condition", "for");
+ return false;
+ }
+ //
+ // condition has the form:
+ // loop_index relational_operator constant_expression
+ //
+ TIntermBinary* binOp = cond->getAsBinaryNode();
+ if (binOp == NULL) {
+ error(node->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ // Loop index should be to the left of relational operator.
+ TIntermSymbol* symbol = binOp->getLeft()->getAsSymbolNode();
+ if (symbol == NULL) {
+ error(binOp->getLine(), "Invalid condition", "for");
+ return false;
+ }
+ if (symbol->getId() != info->index.id) {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+ // Relational operator is one of: > >= < <= == or !=.
+ switch (binOp->getOp()) {
+ case EOpEqual:
+ case EOpNotEqual:
+ case EOpLessThan:
+ case EOpGreaterThan:
+ case EOpLessThanEqual:
+ case EOpGreaterThanEqual:
+ break;
+ default:
+ error(binOp->getLine(),
+ "Invalid relational operator",
+ getOperatorString(binOp->getOp()));
+ break;
+ }
+ // Loop index must be compared with a constant.
+ if (!isConstExpr(binOp->getRight())) {
+ error(binOp->getLine(),
+ "Loop index cannot be compared with non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateForLoopExpr(TIntermLoop* node,
+ TLoopInfo* info)
+{
+ TIntermNode* expr = node->getExpression();
+ if (expr == NULL) {
+ error(node->getLine(), "Missing expression", "for");
+ return false;
+ }
+
+ // for expression has one of the following forms:
+ // loop_index++
+ // loop_index--
+ // loop_index += constant_expression
+ // loop_index -= constant_expression
+ // ++loop_index
+ // --loop_index
+ // The last two forms are not specified in the spec, but I am assuming
+ // its an oversight.
+ TIntermUnary* unOp = expr->getAsUnaryNode();
+ TIntermBinary* binOp = unOp ? NULL : expr->getAsBinaryNode();
+
+ TOperator op = EOpNull;
+ TIntermSymbol* symbol = NULL;
+ if (unOp != NULL) {
+ op = unOp->getOp();
+ symbol = unOp->getOperand()->getAsSymbolNode();
+ } else if (binOp != NULL) {
+ op = binOp->getOp();
+ symbol = binOp->getLeft()->getAsSymbolNode();
+ }
+
+ // The operand must be loop index.
+ if (symbol == NULL) {
+ error(expr->getLine(), "Invalid expression", "for");
+ return false;
+ }
+ if (symbol->getId() != info->index.id) {
+ error(symbol->getLine(),
+ "Expected loop index", symbol->getSymbol().c_str());
+ return false;
+ }
+
+ // The operator is one of: ++ -- += -=.
+ switch (op) {
+ case EOpPostIncrement:
+ case EOpPostDecrement:
+ case EOpPreIncrement:
+ case EOpPreDecrement:
+ ASSERT((unOp != NULL) && (binOp == NULL));
+ break;
+ case EOpAddAssign:
+ case EOpSubAssign:
+ ASSERT((unOp == NULL) && (binOp != NULL));
+ break;
+ default:
+ error(expr->getLine(), "Invalid operator", getOperatorString(op));
+ return false;
+ }
+
+ // Loop index must be incremented/decremented with a constant.
+ if (binOp != NULL) {
+ if (!isConstExpr(binOp->getRight())) {
+ error(binOp->getLine(),
+ "Loop index cannot be modified by non-constant expression",
+ symbol->getSymbol().c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidateLimitations::validateFunctionCall(TIntermAggregate* node)
+{
+ ASSERT(node->getOp() == EOpFunctionCall);
+
+ // If not within loop body, there is nothing to check.
+ if (!withinLoopBody())
+ return true;
+
+ // List of param indices for which loop indices are used as argument.
+ typedef std::vector<int> ParamIndex;
+ ParamIndex pIndex;
+ TIntermSequence& params = node->getSequence();
+ for (TIntermSequence::size_type i = 0; i < params.size(); ++i) {
+ TIntermSymbol* symbol = params[i]->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol))
+ pIndex.push_back(i);
+ }
+ // If none of the loop indices are used as arguments,
+ // there is nothing to check.
+ if (pIndex.empty())
+ return true;
+
+ bool valid = true;
+ TSymbolTable& symbolTable = GlobalParseContext->symbolTable;
+ TSymbol* symbol = symbolTable.find(node->getName());
+ ASSERT(symbol && symbol->isFunction());
+ TFunction* function = static_cast<TFunction*>(symbol);
+ for (ParamIndex::const_iterator i = pIndex.begin();
+ i != pIndex.end(); ++i) {
+ const TParameter& param = function->getParam(*i);
+ TQualifier qual = param.type->getQualifier();
+ if ((qual == EvqOut) || (qual == EvqInOut)) {
+ error(params[*i]->getLine(),
+ "Loop index cannot be used as argument to a function out or inout parameter",
+ params[*i]->getAsSymbolNode()->getSymbol().c_str());
+ valid = false;
+ }
+ }
+
+ return valid;
+}
+
+bool ValidateLimitations::validateOperation(TIntermOperator* node,
+ TIntermNode* operand) {
+ // Check if loop index is modified in the loop body.
+ if (!withinLoopBody() || !node->modifiesState())
+ return true;
+
+ const TIntermSymbol* symbol = operand->getAsSymbolNode();
+ if (symbol && isLoopIndex(symbol)) {
+ error(node->getLine(),
+ "Loop index cannot be statically assigned to within the body of the loop",
+ symbol->getSymbol().c_str());
+ }
+ return true;
+}
+
+bool ValidateLimitations::isConstExpr(TIntermNode* node)
+{
+ ASSERT(node != NULL);
+ return node->getAsConstantUnion() != NULL;
+}
+
+bool ValidateLimitations::isConstIndexExpr(TIntermNode* node)
+{
+ ASSERT(node != NULL);
+
+ ValidateConstIndexExpr validate(mLoopStack);
+ node->traverse(&validate);
+ return validate.isValid();
+}
+
+bool ValidateLimitations::validateIndexing(TIntermBinary* node)
+{
+ ASSERT((node->getOp() == EOpIndexDirect) ||
+ (node->getOp() == EOpIndexIndirect));
+
+ bool valid = true;
+ TIntermTyped* index = node->getRight();
+ // The index expression must have integral type.
+ if (!index->isScalar() || (index->getBasicType() != EbtInt)) {
+ error(index->getLine(),
+ "Index expression must have integral type",
+ index->getCompleteString().c_str());
+ valid = false;
+ }
+ // The index expession must be a constant-index-expression unless
+ // the operand is a uniform in a vertex shader.
+ TIntermTyped* operand = node->getLeft();
+ bool skip = (mShaderType == SH_VERTEX_SHADER) &&
+ (operand->getQualifier() == EvqUniform);
+ if (!skip && !isConstIndexExpr(index)) {
+ error(index->getLine(), "Index expression must be constant", "[]");
+ valid = false;
+ }
+ return valid;
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.h b/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.h
new file mode 100644
index 000000000..dd2e5bf09
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ValidateLimitations.h
@@ -0,0 +1,63 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+class TInfoSinkBase;
+
+struct TLoopInfo {
+ struct TIndex {
+ int id; // symbol id.
+ } index;
+ TIntermLoop* loop;
+};
+typedef TVector<TLoopInfo> TLoopStack;
+
+// Traverses intermediate tree to ensure that the shader does not exceed the
+// minimum functionality mandated in GLSL 1.0 spec, Appendix A.
+class ValidateLimitations : public TIntermTraverser {
+public:
+ ValidateLimitations(ShShaderType shaderType, TInfoSinkBase& sink);
+
+ int numErrors() const { return mNumErrors; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+private:
+ void error(TSourceLoc loc, const char *reason, const char* token);
+
+ bool withinLoopBody() const;
+ bool isLoopIndex(const TIntermSymbol* symbol) const;
+ bool validateLoopType(TIntermLoop* node);
+ bool validateForLoopHeader(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopInit(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopCond(TIntermLoop* node, TLoopInfo* info);
+ bool validateForLoopExpr(TIntermLoop* node, TLoopInfo* info);
+ // Returns true if none of the loop indices is used as the argument to
+ // the given function out or inout parameter.
+ bool validateFunctionCall(TIntermAggregate* node);
+ bool validateOperation(TIntermOperator* node, TIntermNode* operand);
+
+ // Returns true if indexing does not exceed the minimum functionality
+ // mandated in GLSL 1.0 spec, Appendix A, Section 5.
+ bool isConstExpr(TIntermNode* node);
+ bool isConstIndexExpr(TIntermNode* node);
+ bool validateIndexing(TIntermBinary* node);
+
+ ShShaderType mShaderType;
+ TInfoSinkBase& mSink;
+ int mNumErrors;
+ TLoopStack mLoopStack;
+};
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.cpp b/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.cpp
new file mode 100644
index 000000000..a13a89650
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.cpp
@@ -0,0 +1,220 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/VariableInfo.h"
+
+static TString arrayBrackets(int index)
+{
+ TStringStream stream;
+ stream << "[" << index << "]";
+ return stream.str();
+}
+
+// Returns the data type for an attribute or uniform.
+static ShDataType getVariableDataType(const TType& type)
+{
+ switch (type.getBasicType()) {
+ case EbtFloat:
+ if (type.isMatrix()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_FLOAT_MAT2;
+ case 3: return SH_FLOAT_MAT3;
+ case 4: return SH_FLOAT_MAT4;
+ default: UNREACHABLE();
+ }
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_FLOAT_VEC2;
+ case 3: return SH_FLOAT_VEC3;
+ case 4: return SH_FLOAT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_FLOAT;
+ }
+ case EbtInt:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_INT_VEC2;
+ case 3: return SH_INT_VEC3;
+ case 4: return SH_INT_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_INT;
+ }
+ case EbtBool:
+ if (type.isMatrix()) {
+ UNREACHABLE();
+ } else if (type.isVector()) {
+ switch (type.getNominalSize()) {
+ case 2: return SH_BOOL_VEC2;
+ case 3: return SH_BOOL_VEC3;
+ case 4: return SH_BOOL_VEC4;
+ default: UNREACHABLE();
+ }
+ } else {
+ return SH_BOOL;
+ }
+ case EbtSampler2D: return SH_SAMPLER_2D;
+ case EbtSamplerCube: return SH_SAMPLER_CUBE;
+ default: UNREACHABLE();
+ }
+ return SH_NONE;
+}
+
+static void getBuiltInVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList);
+static void getUserDefinedVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList);
+
+// Returns info for an attribute or uniform.
+static void getVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList)
+{
+ if (type.getBasicType() == EbtStruct) {
+ if (type.isArray()) {
+ for (int i = 0; i < type.getArraySize(); ++i) {
+ TString lname = name + arrayBrackets(i);
+ TString lmappedName = mappedName + arrayBrackets(i);
+ getUserDefinedVariableInfo(type, lname, lmappedName, infoList);
+ }
+ } else {
+ getUserDefinedVariableInfo(type, name, mappedName, infoList);
+ }
+ } else {
+ getBuiltInVariableInfo(type, name, mappedName, infoList);
+ }
+}
+
+void getBuiltInVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList)
+{
+ ASSERT(type.getBasicType() != EbtStruct);
+
+ TVariableInfo varInfo;
+ if (type.isArray()) {
+ varInfo.name = (name + "[0]").c_str();
+ varInfo.mappedName = (mappedName + "[0]").c_str();
+ varInfo.size = type.getArraySize();
+ } else {
+ varInfo.name = name.c_str();
+ varInfo.mappedName = mappedName.c_str();
+ varInfo.size = 1;
+ }
+ varInfo.type = getVariableDataType(type);
+ infoList.push_back(varInfo);
+}
+
+void getUserDefinedVariableInfo(const TType& type,
+ const TString& name,
+ const TString& mappedName,
+ TVariableInfoList& infoList)
+{
+ ASSERT(type.getBasicType() == EbtStruct);
+
+ const TTypeList* structure = type.getStruct();
+ for (size_t i = 0; i < structure->size(); ++i) {
+ const TType* fieldType = (*structure)[i].type;
+ getVariableInfo(*fieldType,
+ name + "." + fieldType->getFieldName(),
+ mappedName + "." + fieldType->getFieldName(),
+ infoList);
+ }
+}
+
+CollectAttribsUniforms::CollectAttribsUniforms(TVariableInfoList& attribs,
+ TVariableInfoList& uniforms)
+ : mAttribs(attribs),
+ mUniforms(uniforms)
+{
+}
+
+// We are only interested in attribute and uniform variable declaration.
+void CollectAttribsUniforms::visitSymbol(TIntermSymbol*)
+{
+}
+
+void CollectAttribsUniforms::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool CollectAttribsUniforms::visitBinary(Visit, TIntermBinary*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitUnary(Visit, TIntermUnary*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitSelection(Visit, TIntermSelection*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitAggregate(Visit, TIntermAggregate* node)
+{
+ bool visitChildren = false;
+
+ switch (node->getOp())
+ {
+ case EOpSequence:
+ // We need to visit sequence children to get to variable declarations.
+ visitChildren = true;
+ break;
+ case EOpDeclaration: {
+ const TIntermSequence& sequence = node->getSequence();
+ TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
+ if (qualifier == EvqAttribute || qualifier == EvqUniform)
+ {
+ TVariableInfoList& infoList = qualifier == EvqAttribute ?
+ mAttribs : mUniforms;
+ for (TIntermSequence::const_iterator i = sequence.begin();
+ i != sequence.end(); ++i)
+ {
+ const TIntermSymbol* variable = (*i)->getAsSymbolNode();
+ // The only case in which the sequence will not contain a
+ // TIntermSymbol node is initialization. It will contain a
+ // TInterBinary node in that case. Since attributes and unifroms
+ // cannot be initialized in a shader, we must have only
+ // TIntermSymbol nodes in the sequence.
+ ASSERT(variable != NULL);
+ getVariableInfo(variable->getType(),
+ variable->getOriginalSymbol(),
+ variable->getSymbol(),
+ infoList);
+ }
+ }
+ break;
+ }
+ default: break;
+ }
+
+ return visitChildren;
+}
+
+bool CollectAttribsUniforms::visitLoop(Visit, TIntermLoop*)
+{
+ return false;
+}
+
+bool CollectAttribsUniforms::visitBranch(Visit, TIntermBranch*)
+{
+ return false;
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.h b/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.h
new file mode 100644
index 000000000..667acafcc
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/VariableInfo.h
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_VARIABLE_INFO_H_
+#define COMPILER_VARIABLE_INFO_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+// Provides information about a variable.
+// It is currently being used to store info about active attribs and uniforms.
+struct TVariableInfo {
+ TPersistString name;
+ TPersistString mappedName;
+ ShDataType type;
+ int size;
+};
+typedef std::vector<TVariableInfo> TVariableInfoList;
+
+// Traverses intermediate tree to collect all attributes and uniforms.
+class CollectAttribsUniforms : public TIntermTraverser {
+public:
+ CollectAttribsUniforms(TVariableInfoList& attribs,
+ TVariableInfoList& uniforms);
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+private:
+ TVariableInfoList& mAttribs;
+ TVariableInfoList& mUniforms;
+};
+
+#endif // COMPILER_VARIABLE_INFO_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.cpp b/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.cpp
new file mode 100644
index 000000000..26cee0527
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.cpp
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/VersionGLSL.h"
+
+static const int GLSL_VERSION_110 = 110;
+static const int GLSL_VERSION_120 = 120;
+
+// We need to scan for three things:
+// 1. "invariant" keyword: This can occur in both - vertex and fragment shaders
+// but only at the global scope.
+// 2. "gl_PointCoord" built-in variable: This can only occur in fragment shader
+// but inside any scope.
+// 3. Call to a matrix constructor with another matrix as argument.
+// (These constructors were reserved in GLSL version 1.10.)
+//
+// If it weren't for (3) then we would only need to scan the global
+// scope of the vertex shader. However, we need to scan the entire
+// shader in both cases.
+//
+// TODO(alokp): The following two cases of invariant decalaration get lost
+// during parsing - they do not get carried over to the intermediate tree.
+// Handle these cases:
+// 1. When a pragma is used to force all output variables to be invariant:
+// - #pragma STDGL invariant(all)
+// 2. When a previously decalared or built-in variable is marked invariant:
+// - invariant gl_Position;
+// - varying vec3 color; invariant color;
+//
+TVersionGLSL::TVersionGLSL(ShShaderType type)
+ : mShaderType(type),
+ mVersion(GLSL_VERSION_110)
+{
+}
+
+void TVersionGLSL::visitSymbol(TIntermSymbol* node)
+{
+ if (node->getSymbol() == "gl_PointCoord")
+ updateVersion(GLSL_VERSION_120);
+}
+
+void TVersionGLSL::visitConstantUnion(TIntermConstantUnion*)
+{
+}
+
+bool TVersionGLSL::visitBinary(Visit, TIntermBinary*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitUnary(Visit, TIntermUnary*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitSelection(Visit, TIntermSelection*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitAggregate(Visit, TIntermAggregate* node)
+{
+ bool visitChildren = true;
+
+ switch (node->getOp()) {
+ case EOpSequence:
+ // We need to visit sequence children to get to global or inner scope.
+ visitChildren = true;
+ break;
+ case EOpDeclaration: {
+ const TIntermSequence& sequence = node->getSequence();
+ TQualifier qualifier = sequence.front()->getAsTyped()->getQualifier();
+ if ((qualifier == EvqInvariantVaryingIn) ||
+ (qualifier == EvqInvariantVaryingOut)) {
+ updateVersion(GLSL_VERSION_120);
+ }
+ break;
+ }
+ case EOpConstructMat2:
+ case EOpConstructMat3:
+ case EOpConstructMat4: {
+ const TIntermSequence& sequence = node->getSequence();
+ if (sequence.size() == 1) {
+ TIntermTyped* typed = sequence.front()->getAsTyped();
+ if (typed && typed->isMatrix()) {
+ updateVersion(GLSL_VERSION_120);
+ }
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ return visitChildren;
+}
+
+bool TVersionGLSL::visitLoop(Visit, TIntermLoop*)
+{
+ return true;
+}
+
+bool TVersionGLSL::visitBranch(Visit, TIntermBranch*)
+{
+ return true;
+}
+
+void TVersionGLSL::updateVersion(int version)
+{
+ mVersion = std::max(version, mVersion);
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.h b/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.h
new file mode 100644
index 000000000..376fcb848
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/VersionGLSL.h
@@ -0,0 +1,52 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_VERSIONGLSL_H_
+#define COMPILER_VERSIONGLSL_H_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+
+// Traverses the intermediate tree to return the minimum GLSL version
+// required to legally access all built-in features used in the shader.
+// GLSL 1.1 which is mandated by OpenGL 2.0 provides:
+// - #version and #extension to declare version and extensions.
+// - built-in functions refract, exp, and log.
+// - updated step() to compare x < edge instead of x <= edge.
+// GLSL 1.2 which is mandated by OpenGL 2.1 provides:
+// - many changes to reduce differences when compared to the ES specification.
+// - invariant keyword and its support.
+// - c++ style name hiding rules.
+// - built-in variable gl_PointCoord for fragment shaders.
+// - matrix constructors taking matrix as argument.
+//
+class TVersionGLSL : public TIntermTraverser {
+public:
+ TVersionGLSL(ShShaderType type);
+
+ // Returns 120 if "invariant" keyword, "gl_PointCoord", or
+ // matrix/matrix constructors are used in the shader. Else 110 is
+ // returned.
+ int getVersion() { return mVersion; }
+
+ virtual void visitSymbol(TIntermSymbol*);
+ virtual void visitConstantUnion(TIntermConstantUnion*);
+ virtual bool visitBinary(Visit, TIntermBinary*);
+ virtual bool visitUnary(Visit, TIntermUnary*);
+ virtual bool visitSelection(Visit, TIntermSelection*);
+ virtual bool visitAggregate(Visit, TIntermAggregate*);
+ virtual bool visitLoop(Visit, TIntermLoop*);
+ virtual bool visitBranch(Visit, TIntermBranch*);
+
+protected:
+ void updateVersion(int version);
+
+private:
+ ShShaderType mShaderType;
+ int mVersion;
+};
+
+#endif // COMPILER_VERSIONGLSL_H_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/debug.cpp b/Source/ThirdParty/ANGLE/src/compiler/debug.cpp
new file mode 100644
index 000000000..9642e1e37
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/debug.cpp
@@ -0,0 +1,36 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// debug.cpp: Debugging utilities.
+
+#include "compiler/debug.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "compiler/ParseHelper.h"
+
+static const int kTraceBufferLen = 1024;
+
+#ifdef TRACE_ENABLED
+extern "C" {
+void Trace(const char *format, ...) {
+ if (!format) return;
+
+ TParseContext* parseContext = GetGlobalParseContext();
+ if (parseContext) {
+ char buf[kTraceBufferLen];
+ va_list args;
+ va_start(args, format);
+ vsnprintf(buf, kTraceBufferLen, format, args);
+ va_end(args);
+
+ parseContext->infoSink.debug << buf;
+ }
+}
+} // extern "C"
+#endif // TRACE_ENABLED
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/debug.h b/Source/ThirdParty/ANGLE/src/compiler/debug.h
new file mode 100644
index 000000000..7a371516a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/debug.h
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// debug.h: Debugging utilities.
+
+#ifndef COMPILER_DEBUG_H_
+#define COMPILER_DEBUG_H_
+
+#include <assert.h>
+
+#ifdef _DEBUG
+#define TRACE_ENABLED // define to enable debug message tracing
+#endif // _DEBUG
+
+// Outputs text to the debug log
+#ifdef TRACE_ENABLED
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+void Trace(const char* format, ...);
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#else // TRACE_ENABLED
+
+#define Trace(...) ((void)0)
+
+#endif // TRACE_ENABLED
+
+// A macro asserting a condition and outputting failures to the debug log
+#define ASSERT(expression) do { \
+ if(!(expression)) \
+ Trace("Assert failed: %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \
+ assert(expression); \
+} while(0)
+
+#define UNIMPLEMENTED() do { \
+ Trace("Unimplemented invoked: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+} while(0)
+
+#define UNREACHABLE() do { \
+ Trace("Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \
+ assert(false); \
+} while(0)
+
+#endif // COMPILER_DEBUG_H_
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/generate_glslang_lexer.sh b/Source/ThirdParty/ANGLE/src/compiler/generate_glslang_lexer.sh
new file mode 100644
index 000000000..268479dad
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/generate_glslang_lexer.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Generates GLSL ES lexer - glslang_lex.cpp
+
+script_dir=$(dirname $0)
+input_file=$script_dir/glslang.l
+output_file=$script_dir/glslang_lex.cpp
+flex --noline --nounistd --outfile=$output_file $input_file
diff --git a/Source/ThirdParty/ANGLE/src/compiler/generate_glslang_parser.sh b/Source/ThirdParty/ANGLE/src/compiler/generate_glslang_parser.sh
new file mode 100644
index 000000000..889f5c0db
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/generate_glslang_parser.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+# Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Generates GLSL ES parser - glslang_tab.h and glslang_tab.cpp
+
+script_dir=$(dirname $0)
+input_file=$script_dir/glslang.y
+output_header=$script_dir/glslang_tab.h
+output_source=$script_dir/glslang_tab.cpp
+bison --no-lines --skeleton=yacc.c --defines=$output_header --output=$output_source $input_file
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang.h b/Source/ThirdParty/ANGLE/src/compiler/glslang.h
new file mode 100644
index 000000000..26f1457e8
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/glslang.h
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+struct TParseContext;
+extern int glslang_initialize(TParseContext* context);
+extern int glslang_finalize(TParseContext* context);
+
+extern void glslang_scan(int count,
+ const char* const string[],
+ const int length[],
+ TParseContext* context);
+extern int glslang_parse(TParseContext* context);
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang.l b/Source/ThirdParty/ANGLE/src/compiler/glslang.l
new file mode 100644
index 000000000..5a7c5d52a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/glslang.l
@@ -0,0 +1,570 @@
+/*
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Lex specification for GLSL ES.
+Based on ANSI C grammar, Lex specification:
+http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_glslang_lexer.sh,
+WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
+*/
+
+%top{
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_glslang_lexer.sh. DO NOT EDIT!
+}
+
+%{
+#include "compiler/glslang.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/util.h"
+#include "glslang_tab.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+#pragma warning(disable : 4102)
+#endif
+
+#define YY_USER_ACTION yylval->lex.line = yylineno;
+#define YY_INPUT(buf, result, max_size) \
+ result = string_input(buf, max_size, yyscanner);
+
+static int string_input(char* buf, int max_size, yyscan_t yyscanner);
+static int check_type(yyscan_t yyscanner);
+static int reserved_word(yyscan_t yyscanner);
+%}
+
+%option noyywrap nounput never-interactive
+%option yylineno reentrant bison-bridge
+%option stack
+%option extra-type="TParseContext*"
+%x COMMENT FIELDS
+
+D [0-9]
+L [a-zA-Z_]
+H [a-fA-F0-9]
+E [Ee][+-]?{D}+
+O [0-7]
+
+%%
+
+%{
+ TParseContext* context = yyextra;
+%}
+
+ /* Single-line comments */
+"//"[^\n]* ;
+
+ /* Multi-line comments */
+"/*" { yy_push_state(COMMENT, yyscanner); }
+<COMMENT>. |
+<COMMENT>\n ;
+<COMMENT>"*/" { yy_pop_state(yyscanner); }
+
+"invariant" { return(INVARIANT); }
+"highp" { return(HIGH_PRECISION); }
+"mediump" { return(MEDIUM_PRECISION); }
+"lowp" { return(LOW_PRECISION); }
+"precision" { return(PRECISION); }
+
+"attribute" { return(ATTRIBUTE); }
+"const" { return(CONST_QUAL); }
+"uniform" { return(UNIFORM); }
+"varying" { return(VARYING); }
+
+"break" { return(BREAK); }
+"continue" { return(CONTINUE); }
+"do" { return(DO); }
+"for" { return(FOR); }
+"while" { return(WHILE); }
+
+"if" { return(IF); }
+"else" { return(ELSE); }
+
+"in" { return(IN_QUAL); }
+"out" { return(OUT_QUAL); }
+"inout" { return(INOUT_QUAL); }
+
+"float" { context->lexAfterType = true; return(FLOAT_TYPE); }
+"int" { context->lexAfterType = true; return(INT_TYPE); }
+"void" { context->lexAfterType = true; return(VOID_TYPE); }
+"bool" { context->lexAfterType = true; return(BOOL_TYPE); }
+"true" { yylval->lex.b = true; return(BOOLCONSTANT); }
+"false" { yylval->lex.b = false; return(BOOLCONSTANT); }
+
+"discard" { return(DISCARD); }
+"return" { return(RETURN); }
+
+"mat2" { context->lexAfterType = true; return(MATRIX2); }
+"mat3" { context->lexAfterType = true; return(MATRIX3); }
+"mat4" { context->lexAfterType = true; return(MATRIX4); }
+
+"vec2" { context->lexAfterType = true; return (VEC2); }
+"vec3" { context->lexAfterType = true; return (VEC3); }
+"vec4" { context->lexAfterType = true; return (VEC4); }
+"ivec2" { context->lexAfterType = true; return (IVEC2); }
+"ivec3" { context->lexAfterType = true; return (IVEC3); }
+"ivec4" { context->lexAfterType = true; return (IVEC4); }
+"bvec2" { context->lexAfterType = true; return (BVEC2); }
+"bvec3" { context->lexAfterType = true; return (BVEC3); }
+"bvec4" { context->lexAfterType = true; return (BVEC4); }
+
+"sampler2D" { context->lexAfterType = true; return SAMPLER2D; }
+"samplerCube" { context->lexAfterType = true; return SAMPLERCUBE; }
+
+"struct" { context->lexAfterType = true; return(STRUCT); }
+
+"asm" { return reserved_word(yyscanner); }
+
+"class" { return reserved_word(yyscanner); }
+"union" { return reserved_word(yyscanner); }
+"enum" { return reserved_word(yyscanner); }
+"typedef" { return reserved_word(yyscanner); }
+"template" { return reserved_word(yyscanner); }
+"this" { return reserved_word(yyscanner); }
+"packed" { return reserved_word(yyscanner); }
+
+"goto" { return reserved_word(yyscanner); }
+"switch" { return reserved_word(yyscanner); }
+"default" { return reserved_word(yyscanner); }
+
+"inline" { return reserved_word(yyscanner); }
+"noinline" { return reserved_word(yyscanner); }
+"volatile" { return reserved_word(yyscanner); }
+"public" { return reserved_word(yyscanner); }
+"static" { return reserved_word(yyscanner); }
+"extern" { return reserved_word(yyscanner); }
+"external" { return reserved_word(yyscanner); }
+"interface" { return reserved_word(yyscanner); }
+
+"long" { return reserved_word(yyscanner); }
+"short" { return reserved_word(yyscanner); }
+"double" { return reserved_word(yyscanner); }
+"half" { return reserved_word(yyscanner); }
+"fixed" { return reserved_word(yyscanner); }
+"unsigned" { return reserved_word(yyscanner); }
+
+"input" { return reserved_word(yyscanner); }
+"output" { return reserved_word(yyscanner); }
+
+"hvec2" { return reserved_word(yyscanner); }
+"hvec3" { return reserved_word(yyscanner); }
+"hvec4" { return reserved_word(yyscanner); }
+"fvec2" { return reserved_word(yyscanner); }
+"fvec3" { return reserved_word(yyscanner); }
+"fvec4" { return reserved_word(yyscanner); }
+"dvec2" { return reserved_word(yyscanner); }
+"dvec3" { return reserved_word(yyscanner); }
+"dvec4" { return reserved_word(yyscanner); }
+
+"sizeof" { return reserved_word(yyscanner); }
+"cast" { return reserved_word(yyscanner); }
+
+"namespace" { return reserved_word(yyscanner); }
+"using" { return reserved_word(yyscanner); }
+
+{L}({L}|{D})* {
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+
+0[xX]{H}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+0{O}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+0{D}+ { context->error(yylineno, "Invalid Octal number.", yytext, "", ""); context->recover(); return 0;}
+{D}+ { yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+
+{D}+{E} { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+{D}+"."{D}*({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+"."{D}+({E})? { yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+
+"+=" { return(ADD_ASSIGN); }
+"-=" { return(SUB_ASSIGN); }
+"*=" { return(MUL_ASSIGN); }
+"/=" { return(DIV_ASSIGN); }
+"%=" { return(MOD_ASSIGN); }
+"<<=" { return(LEFT_ASSIGN); }
+">>=" { return(RIGHT_ASSIGN); }
+"&=" { return(AND_ASSIGN); }
+"^=" { return(XOR_ASSIGN); }
+"|=" { return(OR_ASSIGN); }
+
+"++" { return(INC_OP); }
+"--" { return(DEC_OP); }
+"&&" { return(AND_OP); }
+"||" { return(OR_OP); }
+"^^" { return(XOR_OP); }
+"<=" { return(LE_OP); }
+">=" { return(GE_OP); }
+"==" { return(EQ_OP); }
+"!=" { return(NE_OP); }
+"<<" { return(LEFT_OP); }
+">>" { return(RIGHT_OP); }
+";" { context->lexAfterType = false; return(SEMICOLON); }
+("{"|"<%") { context->lexAfterType = false; return(LEFT_BRACE); }
+("}"|"%>") { return(RIGHT_BRACE); }
+"," { if (context->inTypeParen) context->lexAfterType = false; return(COMMA); }
+":" { return(COLON); }
+"=" { context->lexAfterType = false; return(EQUAL); }
+"(" { context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); }
+")" { context->inTypeParen = false; return(RIGHT_PAREN); }
+("["|"<:") { return(LEFT_BRACKET); }
+("]"|":>") { return(RIGHT_BRACKET); }
+"." { BEGIN(FIELDS); return(DOT); }
+"!" { return(BANG); }
+"-" { return(DASH); }
+"~" { return(TILDE); }
+"+" { return(PLUS); }
+"*" { return(STAR); }
+"/" { return(SLASH); }
+"%" { return(PERCENT); }
+"<" { return(LEFT_ANGLE); }
+">" { return(RIGHT_ANGLE); }
+"|" { return(VERTICAL_BAR); }
+"^" { return(CARET); }
+"&" { return(AMPERSAND); }
+"?" { return(QUESTION); }
+
+<FIELDS>{L}({L}|{D})* {
+ BEGIN(INITIAL);
+ yylval->lex.string = NewPoolTString(yytext);
+ return FIELD_SELECTION;
+}
+<FIELDS>[ \t\v\f\r] {}
+
+[ \t\v\n\f\r] { }
+<*><<EOF>> { context->AfterEOF = true; yyterminate(); }
+<*>. { context->warning(yylineno, "Unknown char", yytext, ""); return 0; }
+
+%%
+
+extern "C" {
+// Preprocessor interface.
+#include "compiler/preprocessor/preprocess.h"
+
+#define SETUP_CONTEXT(pp) \
+ TParseContext* context = (TParseContext*) pp->pC; \
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+
+// Preprocessor callbacks.
+void CPPDebugLogMsg(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->infoSink.debug.message(EPrefixNone, msg);
+}
+
+void CPPWarningToInfoLog(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->warning(yylineno, msg, "", "");
+}
+
+void CPPShInfoLogMsg(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->error(yylineno, msg, "", "");
+ context->recover();
+}
+
+void CPPErrorToInfoLog(char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->error(yylineno, msg, "", "");
+ context->recover();
+}
+
+void SetLineNumber(int line)
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0;
+ DecodeSourceLoc(yylineno, &string, NULL);
+ yylineno = EncodeSourceLoc(string, line);
+}
+
+void SetStringNumber(int string)
+{
+ SETUP_CONTEXT(cpp);
+ int line = 0;
+ DecodeSourceLoc(yylineno, NULL, &line);
+ yylineno = EncodeSourceLoc(string, line);
+}
+
+int GetStringNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0;
+ DecodeSourceLoc(yylineno, &string, NULL);
+ return string;
+}
+
+int GetLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int line = 0;
+ DecodeSourceLoc(yylineno, NULL, &line);
+ return line;
+}
+
+void IncLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0, line = 0;
+ DecodeSourceLoc(yylineno, &string, &line);
+ yylineno = EncodeSourceLoc(string, ++line);
+}
+
+void DecLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0, line = 0;
+ DecodeSourceLoc(yylineno, &string, &line);
+ yylineno = EncodeSourceLoc(string, --line);
+}
+
+void HandlePragma(const char **tokens, int numTokens)
+{
+ SETUP_CONTEXT(cpp);
+ if (!strcmp(tokens[0], "optimize")) {
+ if (numTokens != 4) {
+ CPPShInfoLogMsg("optimize pragma syntax is incorrect");
+ return;
+ }
+
+ if (strcmp(tokens[1], "(")) {
+ CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword");
+ return;
+ }
+
+ if (!strcmp(tokens[2], "on"))
+ context->contextPragma.optimize = true;
+ else if (!strcmp(tokens[2], "off"))
+ context->contextPragma.optimize = false;
+ else {
+ CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma");
+ return;
+ }
+
+ if (strcmp(tokens[3], ")")) {
+ CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma");
+ return;
+ }
+ } else if (!strcmp(tokens[0], "debug")) {
+ if (numTokens != 4) {
+ CPPShInfoLogMsg("debug pragma syntax is incorrect");
+ return;
+ }
+
+ if (strcmp(tokens[1], "(")) {
+ CPPShInfoLogMsg("\"(\" expected after 'debug' keyword");
+ return;
+ }
+
+ if (!strcmp(tokens[2], "on"))
+ context->contextPragma.debug = true;
+ else if (!strcmp(tokens[2], "off"))
+ context->contextPragma.debug = false;
+ else {
+ CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma");
+ return;
+ }
+
+ if (strcmp(tokens[3], ")")) {
+ CPPShInfoLogMsg("\")\" expected to end 'debug' pragma");
+ return;
+ }
+ } else {
+#ifdef PRAGMA_TABLE
+ //
+ // implementation specific pragma
+ // use ((TParseContext *)cpp->pC)->contextPragma.pragmaTable to store the information about pragma
+ // For now, just ignore the pragma that the implementation cannot recognize
+ // An Example of one such implementation for a pragma that has a syntax like
+ // #pragma pragmaname(pragmavalue)
+ // This implementation stores the current pragmavalue against the pragma name in pragmaTable.
+ //
+ if (numTokens == 4 && !strcmp(tokens[1], "(") && !strcmp(tokens[3], ")")) {
+ TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable;
+ TPragmaTable::iterator iter;
+ iter = pragmaTable.find(TString(tokens[0]));
+ if (iter != pragmaTable.end()) {
+ iter->second = tokens[2];
+ } else {
+ pragmaTable[ tokens[0] ] = tokens[2];
+ }
+ } else if (numTokens >= 2) {
+ TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable;
+ TPragmaTable::iterator iter;
+ iter = pragmaTable.find(TString(tokens[0]));
+ if (iter != pragmaTable.end()) {
+ iter->second = tokens[1];
+ } else {
+ pragmaTable[ tokens[0] ] = tokens[1];
+ }
+ }
+#endif // PRAGMA_TABLE
+ }
+}
+
+void StoreStr(char *string)
+{
+ SETUP_CONTEXT(cpp);
+ TString strSrc;
+ strSrc = TString(string);
+
+ context->HashErrMsg = context->HashErrMsg + " " + strSrc;
+}
+
+const char* GetStrfromTStr(void)
+{
+ SETUP_CONTEXT(cpp);
+ cpp->ErrMsg = context->HashErrMsg.c_str();
+ return cpp->ErrMsg;
+}
+
+void ResetTString(void)
+{
+ SETUP_CONTEXT(cpp);
+ context->HashErrMsg = "";
+}
+
+TBehavior GetBehavior(const char* behavior)
+{
+ if (!strcmp("require", behavior))
+ return EBhRequire;
+ else if (!strcmp("enable", behavior))
+ return EBhEnable;
+ else if (!strcmp("disable", behavior))
+ return EBhDisable;
+ else if (!strcmp("warn", behavior))
+ return EBhWarn;
+ else {
+ CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str());
+ return EBhDisable;
+ }
+}
+
+void updateExtensionBehavior(const char* extName, const char* behavior)
+{
+ SETUP_CONTEXT(cpp);
+ TBehavior behaviorVal = GetBehavior(behavior);
+ TMap<TString, TBehavior>:: iterator iter;
+ TString msg;
+
+ // special cased for all extension
+ if (!strcmp(extName, "all")) {
+ if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) {
+ CPPShInfoLogMsg("extension 'all' cannot have 'require' or 'enable' behavior");
+ return;
+ } else {
+ for (iter = context->extensionBehavior.begin(); iter != context->extensionBehavior.end(); ++iter)
+ iter->second = behaviorVal;
+ }
+ } else {
+ iter = context->extensionBehavior.find(TString(extName));
+ if (iter == context->extensionBehavior.end()) {
+ switch (behaviorVal) {
+ case EBhRequire:
+ CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str());
+ break;
+ case EBhEnable:
+ case EBhWarn:
+ case EBhDisable:
+ msg = TString("extension '") + extName + "' is not supported";
+ context->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno);
+ break;
+ }
+ return;
+ } else
+ iter->second = behaviorVal;
+ }
+}
+} // extern "C"
+
+int string_input(char* buf, int max_size, yyscan_t yyscanner) {
+ int len;
+
+ if ((len = yylex_CPP(buf, max_size)) == 0)
+ return 0;
+ if (len >= max_size)
+ YY_FATAL_ERROR("input buffer overflow, can't enlarge buffer because scanner uses REJECT");
+
+ buf[len] = ' ';
+ return len+1;
+}
+
+int check_type(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ int token = IDENTIFIER;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext);
+ if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType()) {
+ yyextra->lexAfterType = true;
+ token = TYPE_NAME;
+ }
+ }
+ yylval->lex.symbol = symbol;
+ return token;
+}
+
+int reserved_word(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ yyextra->error(yylineno, "Illegal use of reserved word", yytext, "");
+ yyextra->recover();
+ return 0;
+}
+
+void yyerror(TParseContext* context, const char* reason) {
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+
+ if (context->AfterEOF) {
+ context->error(yylineno, reason, "unexpected EOF", "");
+ } else {
+ context->error(yylineno, reason, yytext, "");
+ }
+ context->recover();
+}
+
+int glslang_initialize(TParseContext* context) {
+ yyscan_t scanner = NULL;
+ if (yylex_init_extra(context, &scanner))
+ return 1;
+
+ context->scanner = scanner;
+ return 0;
+}
+
+int glslang_finalize(TParseContext* context) {
+ yyscan_t scanner = context->scanner;
+ if (scanner == NULL) return 0;
+
+ context->scanner = NULL;
+ return yylex_destroy(scanner);
+}
+
+void glslang_scan(int count, const char* const string[], const int length[],
+ TParseContext* context) {
+ yyrestart(NULL, context->scanner);
+ yyset_lineno(EncodeSourceLoc(0, 1), context->scanner);
+ context->AfterEOF = false;
+
+ // Init preprocessor.
+ cpp->pC = context;
+ cpp->PaWhichStr = 0;
+ cpp->PaArgv = string;
+ cpp->PaArgc = count;
+ cpp->PaStrLen = length;
+ cpp->pastFirstStatement = 0;
+ ScanFromString(string[0]);
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang.y b/Source/ThirdParty/ANGLE/src/compiler/glslang.y
new file mode 100644
index 000000000..d05f44195
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/glslang.y
@@ -0,0 +1,2072 @@
+/*
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Yacc grammar for GLSL ES.
+Based on ANSI C Yacc grammar:
+http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_glslang_parser.sh,
+WHICH GENERATES THE GLSL ES PARSER (glslang_tab.cpp AND glslang_tab.h).
+*/
+
+%{
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_glslang_parser.sh. DO NOT EDIT!
+
+#include "compiler/SymbolTable.h"
+#include "compiler/ParseHelper.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYLEX_PARAM context->scanner
+%}
+
+%expect 1 /* One shift reduce conflict because of if | else */
+%pure-parser
+%parse-param {TParseContext* context}
+
+%union {
+ struct {
+ TSourceLoc line;
+ union {
+ TString *string;
+ float f;
+ int i;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TSourceLoc line;
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TTypeLine typeLine;
+ TTypeList* typeList;
+ };
+ } interm;
+}
+
+%{
+extern int yylex(YYSTYPE* yylval_param, void* yyscanner);
+extern void yyerror(TParseContext* context, const char* reason);
+
+#define FRAG_VERT_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER && \
+ context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex/fragment shaders only ", S, "", ""); \
+ context->recover(); \
+ } \
+}
+
+#define VERTEX_ONLY(S, L) { \
+ if (context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S, "", ""); \
+ context->recover(); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S, "", ""); \
+ context->recover(); \
+ } \
+}
+%}
+
+%token <lex> INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION
+%token <lex> ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE
+%token <lex> BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN
+%token <lex> BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4
+%token <lex> MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING
+%token <lex> STRUCT VOID_TYPE WHILE
+%token <lex> SAMPLER2D SAMPLERCUBE
+
+%token <lex> IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT
+%token <lex> FIELD_SELECTION
+%token <lex> LEFT_OP RIGHT_OP
+%token <lex> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
+%token <lex> AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
+%token <lex> MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
+%token <lex> SUB_ASSIGN
+
+%token <lex> LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT
+%token <lex> COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT
+%token <lex> LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION
+
+%type <interm> assignment_operator unary_operator
+%type <interm.intermTypedNode> variable_identifier primary_expression postfix_expression
+%type <interm.intermTypedNode> expression integer_expression assignment_expression
+%type <interm.intermTypedNode> unary_expression multiplicative_expression additive_expression
+%type <interm.intermTypedNode> relational_expression equality_expression
+%type <interm.intermTypedNode> conditional_expression constant_expression
+%type <interm.intermTypedNode> logical_or_expression logical_xor_expression logical_and_expression
+%type <interm.intermTypedNode> shift_expression and_expression exclusive_or_expression inclusive_or_expression
+%type <interm.intermTypedNode> function_call initializer condition conditionopt
+
+%type <interm.intermNode> translation_unit function_definition
+%type <interm.intermNode> statement simple_statement
+%type <interm.intermAggregate> statement_list compound_statement
+%type <interm.intermNode> declaration_statement selection_statement expression_statement
+%type <interm.intermNode> declaration external_declaration
+%type <interm.intermNode> for_init_statement compound_statement_no_new_scope
+%type <interm.nodePair> selection_rest_statement for_rest_statement
+%type <interm.intermNode> iteration_statement jump_statement statement_no_new_scope
+%type <interm> single_declaration init_declarator_list
+
+%type <interm> parameter_declaration parameter_declarator parameter_type_specifier
+%type <interm.qualifier> parameter_qualifier
+
+%type <interm.precision> precision_qualifier
+%type <interm.type> type_qualifier fully_specified_type type_specifier
+%type <interm.type> type_specifier_no_prec type_specifier_nonarray
+%type <interm.type> struct_specifier
+%type <interm.typeLine> struct_declarator
+%type <interm.typeList> struct_declarator_list struct_declaration struct_declaration_list
+%type <interm.function> function_header function_declarator function_identifier
+%type <interm.function> function_header_with_parameters function_call_header
+%type <interm> function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype
+%type <interm> function_call_or_method
+
+%start translation_unit
+%%
+
+variable_identifier
+ : IDENTIFIER {
+ // The symbol table search was done in the lexical phase
+ const TSymbol* symbol = $1.symbol;
+ const TVariable* variable;
+ if (symbol == 0) {
+ context->error($1.line, "undeclared identifier", $1.string->c_str(), "");
+ context->recover();
+ TType type(EbtFloat, EbpUndefined);
+ TVariable* fakeVariable = new TVariable($1.string, type);
+ context->symbolTable.insert(*fakeVariable);
+ variable = fakeVariable;
+ } else {
+ // This identifier can only be a variable type symbol
+ if (! symbol->isVariable()) {
+ context->error($1.line, "variable expected", $1.string->c_str(), "");
+ context->recover();
+ }
+ variable = static_cast<const TVariable*>(symbol);
+ }
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+
+ if (variable->getType().getQualifier() == EvqConst ) {
+ ConstantUnion* constArray = variable->getConstPointer();
+ TType t(variable->getType());
+ $$ = context->intermediate.addConstantUnion(constArray, t, $1.line);
+ } else
+ $$ = context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(), $1.line);
+ }
+ ;
+
+primary_expression
+ : variable_identifier {
+ $$ = $1;
+ }
+ | INTCONSTANT {
+ //
+ // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders,
+ // check for overflow for constants
+ //
+ if (abs($1.i) >= (1 << 16)) {
+ context->error($1.line, " integer constant overflow", "", "");
+ context->recover();
+ }
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst($1.i);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $1.line);
+ }
+ | FLOATCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst($1.f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), $1.line);
+ }
+ | BOOLCONSTANT {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst($1.b);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $1.line);
+ }
+ | LEFT_PAREN expression RIGHT_PAREN {
+ $$ = $2;
+ }
+ ;
+
+postfix_expression
+ : primary_expression {
+ $$ = $1;
+ }
+ | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET {
+ if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) {
+ if ($1->getAsSymbolNode())
+ context->error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str(), "");
+ else
+ context->error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression", "");
+ context->recover();
+ }
+ if ($1->getType().getQualifier() == EvqConst && $3->getQualifier() == EvqConst) {
+ if ($1->isArray()) { // constant folding for arrays
+ $$ = context->addConstArrayNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line);
+ } else if ($1->isVector()) { // constant folding for vectors
+ TVectorFields fields;
+ fields.num = 1;
+ fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array
+ $$ = context->addConstVectorNode(fields, $1, $2.line);
+ } else if ($1->isMatrix()) { // constant folding for matrices
+ $$ = context->addConstMatrixNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line);
+ }
+ } else {
+ if ($3->getQualifier() == EvqConst) {
+ if (($1->isVector() || $1->isMatrix()) && $1->getType().getNominalSize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !$1->isArray() ) {
+ context->error($2.line, "", "[", "field selection out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
+ context->recover();
+ } else {
+ if ($1->isArray()) {
+ if ($1->getType().getArraySize() == 0) {
+ if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) {
+ if (context->arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.line))
+ context->recover();
+ } else {
+ if (context->arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line))
+ context->recover();
+ }
+ } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) {
+ context->error($2.line, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
+ context->recover();
+ }
+ }
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, $3, $2.line);
+ }
+ } else {
+ if ($1->isArray() && $1->getType().getArraySize() == 0) {
+ context->error($2.line, "", "[", "array must be redeclared with a size before being indexed with a variable");
+ context->recover();
+ }
+
+ $$ = context->intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.line);
+ }
+ }
+ if ($$ == 0) {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), $2.line);
+ } else if ($1->isArray()) {
+ if ($1->getType().getStruct())
+ $$->setType(TType($1->getType().getStruct(), $1->getType().getTypeName()));
+ else
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, $1->getNominalSize(), $1->isMatrix()));
+
+ if ($1->getType().getQualifier() == EvqConst)
+ $$->getTypePointer()->setQualifier(EvqConst);
+ } else if ($1->isMatrix() && $1->getType().getQualifier() == EvqConst)
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, $1->getNominalSize()));
+ else if ($1->isMatrix())
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, $1->getNominalSize()));
+ else if ($1->isVector() && $1->getType().getQualifier() == EvqConst)
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst));
+ else if ($1->isVector())
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary));
+ else
+ $$->setType($1->getType());
+ }
+ | function_call {
+ $$ = $1;
+ }
+ | postfix_expression DOT FIELD_SELECTION {
+ if ($1->isArray()) {
+ context->error($3.line, "cannot apply dot operator to an array", ".", "");
+ context->recover();
+ }
+
+ if ($1->isVector()) {
+ TVectorFields fields;
+ if (! context->parseVectorFields(*$3.string, $1->getNominalSize(), fields, $3.line)) {
+ fields.num = 1;
+ fields.offsets[0] = 0;
+ context->recover();
+ }
+
+ if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields
+ $$ = context->addConstVectorNode(fields, $1, $3.line);
+ if ($$ == 0) {
+ context->recover();
+ $$ = $1;
+ }
+ else
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqConst, (int) (*$3.string).size()));
+ } else {
+ if (fields.num == 1) {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.offsets[0]);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line);
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision()));
+ } else {
+ TString vectorString = *$3.string;
+ TIntermTyped* index = context->intermediate.addSwizzle(fields, $3.line);
+ $$ = context->intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(), EvqTemporary, (int) vectorString.size()));
+ }
+ }
+ } else if ($1->isMatrix()) {
+ TMatrixFields fields;
+ if (! context->parseMatrixFields(*$3.string, $1->getNominalSize(), fields, $3.line)) {
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = 0;
+ fields.col = 0;
+ context->recover();
+ }
+
+ if (fields.wholeRow || fields.wholeCol) {
+ context->error($2.line, " non-scalar fields not implemented yet", ".", "");
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(0);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line);
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision(),EvqTemporary, $1->getNominalSize()));
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), $3.line);
+ $$ = context->intermediate.addIndex(EOpIndexDirect, $1, index, $2.line);
+ $$->setType(TType($1->getBasicType(), $1->getPrecision()));
+ }
+ } else if ($1->getBasicType() == EbtStruct) {
+ bool fieldFound = false;
+ const TTypeList* fields = $1->getType().getStruct();
+ if (fields == 0) {
+ context->error($2.line, "structure has no fields", "Internal Error", "");
+ context->recover();
+ $$ = $1;
+ } else {
+ unsigned int i;
+ for (i = 0; i < fields->size(); ++i) {
+ if ((*fields)[i].type->getFieldName() == *$3.string) {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound) {
+ if ($1->getType().getQualifier() == EvqConst) {
+ $$ = context->addConstStruct(*$3.string, $1, $2.line);
+ if ($$ == 0) {
+ context->recover();
+ $$ = $1;
+ }
+ else {
+ $$->setType(*(*fields)[i].type);
+ // change the qualifier of the return type, not of the structure field
+ // as the structure definition is shared between various structures.
+ $$->getTypePointer()->setQualifier(EvqConst);
+ }
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(i);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *(*fields)[i].type, $3.line);
+ $$ = context->intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.line);
+ $$->setType(*(*fields)[i].type);
+ }
+ } else {
+ context->error($2.line, " no such field in structure", $3.string->c_str(), "");
+ context->recover();
+ $$ = $1;
+ }
+ }
+ } else {
+ context->error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str(), "");
+ context->recover();
+ $$ = $1;
+ }
+ // don't delete $3.string, it's from the pool
+ }
+ | postfix_expression INC_OP {
+ if (context->lValueErrorCheck($2.line, "++", $1))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPostIncrement, $1, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError($2.line, "++", $1->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | postfix_expression DEC_OP {
+ if (context->lValueErrorCheck($2.line, "--", $1))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPostDecrement, $1, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError($2.line, "--", $1->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+integer_expression
+ : expression {
+ if (context->integerErrorCheck($1, "[]"))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+function_call
+ : function_call_or_method {
+ TFunction* fnCall = $1.function;
+ TOperator op = fnCall->getBuiltInOp();
+
+ if (op != EOpNull)
+ {
+ //
+ // Then this should be a constructor.
+ // Don't go through the symbol table for constructors.
+ // Their parameters will be verified algorithmically.
+ //
+ TType type(EbtVoid, EbpUndefined); // use this to get the type back
+ if (context->constructorErrorCheck($1.line, $1.intermNode, *fnCall, op, &type)) {
+ $$ = 0;
+ } else {
+ //
+ // It's a constructor, of type 'type'.
+ //
+ $$ = context->addConstructor($1.intermNode, &type, op, fnCall, $1.line);
+ }
+
+ if ($$ == 0) {
+ context->recover();
+ $$ = context->intermediate.setAggregateOperator(0, op, $1.line);
+ }
+ $$->setType(type);
+ } else {
+ //
+ // Not a constructor. Find it in the symbol table.
+ //
+ const TFunction* fnCandidate;
+ bool builtIn;
+ fnCandidate = context->findFunction($1.line, fnCall, &builtIn);
+ if (fnCandidate) {
+ //
+ // A declared function.
+ //
+ if (builtIn && !fnCandidate->getExtension().empty() &&
+ context->extensionErrorCheck($1.line, fnCandidate->getExtension())) {
+ context->recover();
+ }
+ op = fnCandidate->getBuiltInOp();
+ if (builtIn && op != EOpNull) {
+ //
+ // A function call mapped to a built-in operation.
+ //
+ if (fnCandidate->getParamCount() == 1) {
+ //
+ // Treat it like a built-in unary operator.
+ //
+ $$ = context->intermediate.addUnaryMath(op, $1.intermNode, 0, context->symbolTable);
+ if ($$ == 0) {
+ context->error($1.intermNode->getLine(), " wrong operand type", "Internal Error",
+ "built in unary operator function. Type: %s",
+ static_cast<TIntermTyped*>($1.intermNode)->getCompleteString().c_str());
+ YYERROR;
+ }
+ } else {
+ $$ = context->intermediate.setAggregateOperator($1.intermAggregate, op, $1.line);
+ }
+ } else {
+ // This is a real function call
+
+ $$ = context->intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, $1.line);
+ $$->setType(fnCandidate->getReturnType());
+
+ // this is how we know whether the given function is a builtIn function or a user defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+ // if builtIn == true, it's definitely a builtIn function with EOpNull
+ if (!builtIn)
+ $$->getAsAggregate()->setUserDefined();
+ $$->getAsAggregate()->setName(fnCandidate->getMangledName());
+
+ TQualifier qual;
+ for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
+ qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut) {
+ if (context->lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) {
+ context->error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", "");
+ context->recover();
+ }
+ }
+ }
+ }
+ $$->setType(fnCandidate->getReturnType());
+ } else {
+ // error message was put out by PaFindFunction()
+ // Put on a dummy node for error recovery
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), $1.line);
+ context->recover();
+ }
+ }
+ delete fnCall;
+ }
+ ;
+
+function_call_or_method
+ : function_call_generic {
+ $$ = $1;
+ }
+ | postfix_expression DOT function_call_generic {
+ context->error($3.line, "methods are not supported", "", "");
+ context->recover();
+ $$ = $3;
+ }
+ ;
+
+function_call_generic
+ : function_call_header_with_parameters RIGHT_PAREN {
+ $$ = $1;
+ $$.line = $2.line;
+ }
+ | function_call_header_no_parameters RIGHT_PAREN {
+ $$ = $1;
+ $$.line = $2.line;
+ }
+ ;
+
+function_call_header_no_parameters
+ : function_call_header VOID_TYPE {
+ $$.function = $1;
+ $$.intermNode = 0;
+ }
+ | function_call_header {
+ $$.function = $1;
+ $$.intermNode = 0;
+ }
+ ;
+
+function_call_header_with_parameters
+ : function_call_header assignment_expression {
+ TParameter param = { 0, new TType($2->getType()) };
+ $1->addParameter(param);
+ $$.function = $1;
+ $$.intermNode = $2;
+ }
+ | function_call_header_with_parameters COMMA assignment_expression {
+ TParameter param = { 0, new TType($3->getType()) };
+ $1.function->addParameter(param);
+ $$.function = $1.function;
+ $$.intermNode = context->intermediate.growAggregate($1.intermNode, $3, $2.line);
+ }
+ ;
+
+function_call_header
+ : function_identifier LEFT_PAREN {
+ $$ = $1;
+ }
+ ;
+
+// Grammar Note: Constructors look like functions, but are recognized as types.
+
+function_identifier
+ : type_specifier_nonarray {
+ //
+ // Constructor
+ //
+ TOperator op = EOpNull;
+ if ($1.userDef) {
+ op = EOpConstructStruct;
+ } else {
+ switch ($1.type) {
+ case EbtFloat:
+ if ($1.matrix) {
+ switch($1.size) {
+ case 2: op = EOpConstructMat2; break;
+ case 3: op = EOpConstructMat3; break;
+ case 4: op = EOpConstructMat4; break;
+ }
+ } else {
+ switch($1.size) {
+ case 1: op = EOpConstructFloat; break;
+ case 2: op = EOpConstructVec2; break;
+ case 3: op = EOpConstructVec3; break;
+ case 4: op = EOpConstructVec4; break;
+ }
+ }
+ break;
+ case EbtInt:
+ switch($1.size) {
+ case 1: op = EOpConstructInt; break;
+ case 2: FRAG_VERT_ONLY("ivec2", $1.line); op = EOpConstructIVec2; break;
+ case 3: FRAG_VERT_ONLY("ivec3", $1.line); op = EOpConstructIVec3; break;
+ case 4: FRAG_VERT_ONLY("ivec4", $1.line); op = EOpConstructIVec4; break;
+ }
+ break;
+ case EbtBool:
+ switch($1.size) {
+ case 1: op = EOpConstructBool; break;
+ case 2: FRAG_VERT_ONLY("bvec2", $1.line); op = EOpConstructBVec2; break;
+ case 3: FRAG_VERT_ONLY("bvec3", $1.line); op = EOpConstructBVec3; break;
+ case 4: FRAG_VERT_ONLY("bvec4", $1.line); op = EOpConstructBVec4; break;
+ }
+ break;
+ default: break;
+ }
+ if (op == EOpNull) {
+ context->error($1.line, "cannot construct this type", getBasicString($1.type), "");
+ context->recover();
+ $1.type = EbtFloat;
+ op = EOpConstructFloat;
+ }
+ }
+ TString tempString;
+ TType type($1);
+ TFunction *function = new TFunction(&tempString, type, op);
+ $$ = function;
+ }
+ | IDENTIFIER {
+ if (context->reservedErrorCheck($1.line, *$1.string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction($1.string, type);
+ $$ = function;
+ }
+ | FIELD_SELECTION {
+ if (context->reservedErrorCheck($1.line, *$1.string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction($1.string, type);
+ $$ = function;
+ }
+ ;
+
+unary_expression
+ : postfix_expression {
+ $$ = $1;
+ }
+ | INC_OP unary_expression {
+ if (context->lValueErrorCheck($1.line, "++", $2))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPreIncrement, $2, $1.line, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError($1.line, "++", $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ }
+ | DEC_OP unary_expression {
+ if (context->lValueErrorCheck($1.line, "--", $2))
+ context->recover();
+ $$ = context->intermediate.addUnaryMath(EOpPreDecrement, $2, $1.line, context->symbolTable);
+ if ($$ == 0) {
+ context->unaryOpError($1.line, "--", $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ }
+ | unary_operator unary_expression {
+ if ($1.op != EOpNull) {
+ $$ = context->intermediate.addUnaryMath($1.op, $2, $1.line, context->symbolTable);
+ if ($$ == 0) {
+ const char* errorOp = "";
+ switch($1.op) {
+ case EOpNegative: errorOp = "-"; break;
+ case EOpLogicalNot: errorOp = "!"; break;
+ default: break;
+ }
+ context->unaryOpError($1.line, errorOp, $2->getCompleteString());
+ context->recover();
+ $$ = $2;
+ }
+ } else
+ $$ = $2;
+ }
+ ;
+// Grammar Note: No traditional style type casts.
+
+unary_operator
+ : PLUS { $$.line = $1.line; $$.op = EOpNull; }
+ | DASH { $$.line = $1.line; $$.op = EOpNegative; }
+ | BANG { $$.line = $1.line; $$.op = EOpLogicalNot; }
+ ;
+// Grammar Note: No '*' or '&' unary ops. Pointers are not supported.
+
+multiplicative_expression
+ : unary_expression { $$ = $1; }
+ | multiplicative_expression STAR unary_expression {
+ FRAG_VERT_ONLY("*", $2.line);
+ $$ = context->intermediate.addBinaryMath(EOpMul, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "*", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | multiplicative_expression SLASH unary_expression {
+ FRAG_VERT_ONLY("/", $2.line);
+ $$ = context->intermediate.addBinaryMath(EOpDiv, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "/", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+additive_expression
+ : multiplicative_expression { $$ = $1; }
+ | additive_expression PLUS multiplicative_expression {
+ $$ = context->intermediate.addBinaryMath(EOpAdd, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "+", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ | additive_expression DASH multiplicative_expression {
+ $$ = context->intermediate.addBinaryMath(EOpSub, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "-", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+shift_expression
+ : additive_expression { $$ = $1; }
+ ;
+
+relational_expression
+ : shift_expression { $$ = $1; }
+ | relational_expression LEFT_ANGLE shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLessThan, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "<", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ | relational_expression RIGHT_ANGLE shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpGreaterThan, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, ">", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ | relational_expression LE_OP shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "<=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ | relational_expression GE_OP shift_expression {
+ $$ = context->intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, ">=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+equality_expression
+ : relational_expression { $$ = $1; }
+ | equality_expression EQ_OP relational_expression {
+ $$ = context->intermediate.addBinaryMath(EOpEqual, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "==", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ | equality_expression NE_OP relational_expression {
+ $$ = context->intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "!=", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+and_expression
+ : equality_expression { $$ = $1; }
+ ;
+
+exclusive_or_expression
+ : and_expression { $$ = $1; }
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression { $$ = $1; }
+ ;
+
+logical_and_expression
+ : inclusive_or_expression { $$ = $1; }
+ | logical_and_expression AND_OP inclusive_or_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "&&", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+logical_xor_expression
+ : logical_and_expression { $$ = $1; }
+ | logical_xor_expression XOR_OP logical_and_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalXor, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "^^", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+logical_or_expression
+ : logical_xor_expression { $$ = $1; }
+ | logical_or_expression OR_OP logical_xor_expression {
+ $$ = context->intermediate.addBinaryMath(EOpLogicalOr, $1, $3, $2.line, context->symbolTable);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, "||", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ $$ = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), $2.line);
+ }
+ }
+ ;
+
+conditional_expression
+ : logical_or_expression { $$ = $1; }
+ | logical_or_expression QUESTION expression COLON assignment_expression {
+ if (context->boolErrorCheck($2.line, $1))
+ context->recover();
+
+ $$ = context->intermediate.addSelection($1, $3, $5, $2.line);
+ if ($3->getType() != $5->getType())
+ $$ = 0;
+
+ if ($$ == 0) {
+ context->binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString());
+ context->recover();
+ $$ = $5;
+ }
+ }
+ ;
+
+assignment_expression
+ : conditional_expression { $$ = $1; }
+ | unary_expression assignment_operator assignment_expression {
+ if (context->lValueErrorCheck($2.line, "assign", $1))
+ context->recover();
+ $$ = context->intermediate.addAssign($2.op, $1, $3, $2.line);
+ if ($$ == 0) {
+ context->assignError($2.line, "assign", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $1;
+ }
+ }
+ ;
+
+assignment_operator
+ : EQUAL { $$.line = $1.line; $$.op = EOpAssign; }
+ | MUL_ASSIGN { FRAG_VERT_ONLY("*=", $1.line); $$.line = $1.line; $$.op = EOpMulAssign; }
+ | DIV_ASSIGN { FRAG_VERT_ONLY("/=", $1.line); $$.line = $1.line; $$.op = EOpDivAssign; }
+ | ADD_ASSIGN { $$.line = $1.line; $$.op = EOpAddAssign; }
+ | SUB_ASSIGN { $$.line = $1.line; $$.op = EOpSubAssign; }
+ ;
+
+expression
+ : assignment_expression {
+ $$ = $1;
+ }
+ | expression COMMA assignment_expression {
+ $$ = context->intermediate.addComma($1, $3, $2.line);
+ if ($$ == 0) {
+ context->binaryOpError($2.line, ",", $1->getCompleteString(), $3->getCompleteString());
+ context->recover();
+ $$ = $3;
+ }
+ }
+ ;
+
+constant_expression
+ : conditional_expression {
+ if (context->constErrorCheck($1))
+ context->recover();
+ $$ = $1;
+ }
+ ;
+
+declaration
+ : function_prototype SEMICOLON {
+ TFunction &function = *($1.function);
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getName());
+
+ for (int i = 0; i < function.getParamCount(); i++)
+ {
+ const TParameter &param = function.getParam(i);
+ if (param.name != 0)
+ {
+ TVariable *variable = new TVariable(param.name, *param.type);
+
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), $1.line), $1.line);
+ }
+ else
+ {
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, $1.line), $1.line);
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+ $$ = prototype;
+ }
+ | init_declarator_list SEMICOLON {
+ if ($1.intermAggregate)
+ $1.intermAggregate->setOp(EOpDeclaration);
+ $$ = $1.intermAggregate;
+ }
+ | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON {
+ context->symbolTable.setDefaultPrecision( $3.type, $2 );
+ $$ = 0;
+ }
+ ;
+
+function_prototype
+ : function_declarator RIGHT_PAREN {
+ //
+ // Multiple declarations of the same function are allowed.
+ //
+ // If this is a definition, the definition production code will check for redefinitions
+ // (we don't know at this point if it's a definition or not).
+ //
+ // Redeclarations are allowed. But, return types and parameter qualifiers must match.
+ //
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find($1->getMangledName()));
+ if (prevDec) {
+ if (prevDec->getReturnType() != $1->getReturnType()) {
+ context->error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString(), "");
+ context->recover();
+ }
+ for (int i = 0; i < prevDec->getParamCount(); ++i) {
+ if (prevDec->getParam(i).type->getQualifier() != $1->getParam(i).type->getQualifier()) {
+ context->error($2.line, "overloaded functions must have the same parameter qualifiers", $1->getParam(i).type->getQualifierString(), "");
+ context->recover();
+ }
+ }
+ }
+
+ //
+ // If this is a redeclaration, it could also be a definition,
+ // in which case, we want to use the variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ $$.function = $1;
+ $$.line = $2.line;
+
+ context->symbolTable.insert(*$$.function);
+ }
+ ;
+
+function_declarator
+ : function_header {
+ $$ = $1;
+ }
+ | function_header_with_parameters {
+ $$ = $1;
+ }
+ ;
+
+
+function_header_with_parameters
+ : function_header parameter_declaration {
+ // Add the parameter
+ $$ = $1;
+ if ($2.param.type->getBasicType() != EbtVoid)
+ $1->addParameter($2.param);
+ else
+ delete $2.param.type;
+ }
+ | function_header_with_parameters COMMA parameter_declaration {
+ //
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ //
+ if ($3.param.type->getBasicType() == EbtVoid) {
+ //
+ // This parameter > first is void
+ //
+ context->error($2.line, "cannot be an argument type except for '(void)'", "void", "");
+ context->recover();
+ delete $3.param.type;
+ } else {
+ // Add the parameter
+ $$ = $1;
+ $1->addParameter($3.param);
+ }
+ }
+ ;
+
+function_header
+ : fully_specified_type IDENTIFIER LEFT_PAREN {
+ if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) {
+ context->error($2.line, "no qualifiers allowed for function return", getQualifierString($1.qualifier), "");
+ context->recover();
+ }
+ // make sure a sampler is not involved as well...
+ if (context->structQualifierErrorCheck($2.line, $1))
+ context->recover();
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ TFunction *function;
+ TType type($1);
+ function = new TFunction($2.string, type);
+ $$ = function;
+ }
+ ;
+
+parameter_declarator
+ // Type + name
+ : type_specifier IDENTIFIER {
+ if ($1.type == EbtVoid) {
+ context->error($2.line, "illegal use of type 'void'", $2.string->c_str(), "");
+ context->recover();
+ }
+ if (context->reservedErrorCheck($2.line, *$2.string))
+ context->recover();
+ TParameter param = {$2.string, new TType($1)};
+ $$.line = $2.line;
+ $$.param = param;
+ }
+ | type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ // Check that we can make an array out of this type
+ if (context->arrayTypeErrorCheck($3.line, $1))
+ context->recover();
+
+ if (context->reservedErrorCheck($2.line, *$2.string))
+ context->recover();
+
+ int size;
+ if (context->arraySizeErrorCheck($3.line, $4, size))
+ context->recover();
+ $1.setArray(true, size);
+
+ TType* type = new TType($1);
+ TParameter param = { $2.string, type };
+ $$.line = $2.line;
+ $$.param = param;
+ }
+ ;
+
+parameter_declaration
+ //
+ // The only parameter qualifier a parameter can have are
+ // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST.
+ //
+
+ //
+ // Type + name
+ //
+ : type_qualifier parameter_qualifier parameter_declarator {
+ $$ = $3;
+ if (context->paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type))
+ context->recover();
+ }
+ | parameter_qualifier parameter_declarator {
+ $$ = $2;
+ if (context->parameterSamplerErrorCheck($2.line, $1, *$2.param.type))
+ context->recover();
+ if (context->paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type))
+ context->recover();
+ }
+ //
+ // Only type
+ //
+ | type_qualifier parameter_qualifier parameter_type_specifier {
+ $$ = $3;
+ if (context->paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type))
+ context->recover();
+ }
+ | parameter_qualifier parameter_type_specifier {
+ $$ = $2;
+ if (context->parameterSamplerErrorCheck($2.line, $1, *$2.param.type))
+ context->recover();
+ if (context->paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type))
+ context->recover();
+ }
+ ;
+
+parameter_qualifier
+ : /* empty */ {
+ $$ = EvqIn;
+ }
+ | IN_QUAL {
+ $$ = EvqIn;
+ }
+ | OUT_QUAL {
+ $$ = EvqOut;
+ }
+ | INOUT_QUAL {
+ $$ = EvqInOut;
+ }
+ ;
+
+parameter_type_specifier
+ : type_specifier {
+ TParameter param = { 0, new TType($1) };
+ $$.param = param;
+ }
+ ;
+
+init_declarator_list
+ : single_declaration {
+ $$ = $1;
+ }
+ | init_declarator_list COMMA IDENTIFIER {
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$3.string, TType($1.type), $3.line);
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, symbol, $3.line);
+
+ if (context->structQualifierErrorCheck($3.line, $$.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($3.line, *$3.string, $$.type))
+ context->recover();
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck($3.line, *$3.string, $$.type, variable))
+ context->recover();
+ if (symbol && variable)
+ symbol->setId(variable->getUniqueId());
+ }
+ | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {
+ if (context->structQualifierErrorCheck($3.line, $1.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type))
+ context->recover();
+
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type))
+ context->recover();
+ else {
+ $1.type.setArray(true);
+ TVariable* variable;
+ if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable))
+ context->recover();
+ }
+ }
+ | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ if (context->structQualifierErrorCheck($3.line, $1.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($3.line, *$3.string, $1.type))
+ context->recover();
+
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck($4.line, $1.type) || context->arrayQualifierErrorCheck($4.line, $1.type))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck($4.line, $5, size))
+ context->recover();
+ $1.type.setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck($4.line, *$3.string, $1.type, variable))
+ context->recover();
+ TType type = TType($1.type);
+ type.setArraySize(size);
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *$3.string, type, $3.line), $3.line);
+ }
+ }
+ | init_declarator_list COMMA IDENTIFIER EQUAL initializer {
+ if (context->structQualifierErrorCheck($3.line, $1.type))
+ context->recover();
+
+ $$ = $1;
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) {
+ //
+ // build the intermediate representation
+ //
+ if (intermNode)
+ $$.intermAggregate = context->intermediate.growAggregate($1.intermNode, intermNode, $4.line);
+ else
+ $$.intermAggregate = $1.intermAggregate;
+ } else {
+ context->recover();
+ $$.intermAggregate = 0;
+ }
+ }
+ ;
+
+single_declaration
+ : fully_specified_type {
+ $$.type = $1;
+ $$.intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType($1), $1.line), $1.line);
+ }
+ | fully_specified_type IDENTIFIER {
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
+
+ if (context->structQualifierErrorCheck($2.line, $$.type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($2.line, *$2.string, $$.type))
+ context->recover();
+
+ $$.type = $1;
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck($2.line, *$2.string, $$.type, variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET {
+ context->error($2.line, "unsized array declarations not supported", $2.string->c_str(), "");
+ context->recover();
+
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, TType($1), $2.line);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
+ $$.type = $1;
+ }
+ | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ TType type = TType($1);
+ int size;
+ if (context->arraySizeErrorCheck($2.line, $4, size))
+ context->recover();
+ type.setArraySize(size);
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *$2.string, type, $2.line);
+ $$.intermAggregate = context->intermediate.makeAggregate(symbol, $2.line);
+
+ if (context->structQualifierErrorCheck($2.line, $1))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck($2.line, *$2.string, $1))
+ context->recover();
+
+ $$.type = $1;
+
+ if (context->arrayTypeErrorCheck($3.line, $1) || context->arrayQualifierErrorCheck($3.line, $1))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck($3.line, $4, size))
+ context->recover();
+
+ $1.setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck($3.line, *$2.string, $1, variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ }
+ | fully_specified_type IDENTIFIER EQUAL initializer {
+ if (context->structQualifierErrorCheck($2.line, $1))
+ context->recover();
+
+ $$.type = $1;
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode)) {
+ //
+ // Build intermediate representation
+ //
+ if(intermNode)
+ $$.intermAggregate = context->intermediate.makeAggregate(intermNode, $3.line);
+ else
+ $$.intermAggregate = 0;
+ } else {
+ context->recover();
+ $$.intermAggregate = 0;
+ }
+ }
+ | INVARIANT IDENTIFIER {
+ VERTEX_ONLY("invariant declaration", $1.line);
+ $$.qualifier = EvqInvariantVaryingOut;
+ $$.intermAggregate = 0;
+ }
+
+//
+// Place holder for the pack/unpack languages.
+//
+// | buffer_specifier {
+// $$.intermAggregate = 0;
+// }
+ ;
+
+// Grammar Note: No 'enum', or 'typedef'.
+
+//
+// Place holder for the pack/unpack languages.
+//
+//%type <interm> buffer_declaration
+//%type <interm.type> buffer_specifier input_or_output buffer_declaration_list
+//buffer_specifier
+// : input_or_output LEFT_BRACE buffer_declaration_list RIGHT_BRACE {
+// }
+// ;
+//
+//input_or_output
+// : INPUT {
+// if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "input"))
+// context->recover();
+// UNPACK_ONLY("input", $1.line);
+// $$.qualifier = EvqInput;
+// }
+// | OUTPUT {
+// if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "output"))
+// context->recover();
+// PACK_ONLY("output", $1.line);
+// $$.qualifier = EvqOutput;
+// }
+// ;
+
+//
+// Place holder for the pack/unpack languages.
+//
+//buffer_declaration_list
+// : buffer_declaration {
+// }
+// | buffer_declaration_list buffer_declaration {
+// }
+// ;
+
+//
+// Input/output semantics:
+// float must be 16 or 32 bits
+// float alignment restrictions?
+// check for only one input and only one output
+// sum of bitfields has to be multiple of 32
+//
+
+//
+// Place holder for the pack/unpack languages.
+//
+//buffer_declaration
+// : type_specifier IDENTIFIER COLON constant_expression SEMICOLON {
+// if (context->reservedErrorCheck($2.line, *$2.string, context))
+// context->recover();
+// $$.variable = new TVariable($2.string, $1);
+// if (! context->symbolTable.insert(*$$.variable)) {
+// context->error($2.line, "redefinition", $$.variable->getName().c_str(), "");
+// context->recover();
+// // don't have to delete $$.variable, the pool pop will take care of it
+// }
+// }
+// ;
+
+fully_specified_type
+ : type_specifier {
+ $$ = $1;
+
+ if ($1.array) {
+ context->error($1.line, "not supported", "first-class array", "");
+ context->recover();
+ $1.setArray(false);
+ }
+ }
+ | type_qualifier type_specifier {
+ if ($2.array) {
+ context->error($2.line, "not supported", "first-class array", "");
+ context->recover();
+ $2.setArray(false);
+ }
+
+ if ($1.qualifier == EvqAttribute &&
+ ($2.type == EbtBool || $2.type == EbtInt)) {
+ context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), "");
+ context->recover();
+ }
+ if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) &&
+ ($2.type == EbtBool || $2.type == EbtInt)) {
+ context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), "");
+ context->recover();
+ }
+ $$ = $2;
+ $$.qualifier = $1.qualifier;
+ }
+ ;
+
+type_qualifier
+ : CONST_QUAL {
+ $$.setBasic(EbtVoid, EvqConst, $1.line);
+ }
+ | ATTRIBUTE {
+ VERTEX_ONLY("attribute", $1.line);
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "attribute"))
+ context->recover();
+ $$.setBasic(EbtVoid, EvqAttribute, $1.line);
+ }
+ | VARYING {
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqVaryingOut, $1.line);
+ else
+ $$.setBasic(EbtVoid, EvqVaryingIn, $1.line);
+ }
+ | INVARIANT VARYING {
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ $$.setBasic(EbtVoid, EvqInvariantVaryingOut, $1.line);
+ else
+ $$.setBasic(EbtVoid, EvqInvariantVaryingIn, $1.line);
+ }
+ | UNIFORM {
+ if (context->globalErrorCheck($1.line, context->symbolTable.atGlobalLevel(), "uniform"))
+ context->recover();
+ $$.setBasic(EbtVoid, EvqUniform, $1.line);
+ }
+ ;
+
+type_specifier
+ : type_specifier_no_prec {
+ $$ = $1;
+
+ if ($$.precision == EbpUndefined) {
+ $$.precision = context->symbolTable.getDefaultPrecision($1.type);
+ if (context->precisionErrorCheck($1.line, $$.precision, $1.type)) {
+ context->recover();
+ }
+ }
+ }
+ | precision_qualifier type_specifier_no_prec {
+ $$ = $2;
+ $$.precision = $1;
+ }
+ ;
+
+precision_qualifier
+ : HIGH_PRECISION {
+ $$ = EbpHigh;
+ }
+ | MEDIUM_PRECISION {
+ $$ = EbpMedium;
+ }
+ | LOW_PRECISION {
+ $$ = EbpLow;
+ }
+ ;
+
+type_specifier_no_prec
+ : type_specifier_nonarray {
+ $$ = $1;
+ }
+ | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ $$ = $1;
+
+ if (context->arrayTypeErrorCheck($2.line, $1))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck($2.line, $3, size))
+ context->recover();
+ $$.setArray(true, size);
+ }
+ }
+ ;
+
+type_specifier_nonarray
+ : VOID_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtVoid, qual, $1.line);
+ }
+ | FLOAT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ }
+ | INT_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, $1.line);
+ }
+ | BOOL_TYPE {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, $1.line);
+ }
+// | UNSIGNED INT_TYPE {
+// PACK_UNPACK_ONLY("unsigned", $1.line);
+// TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+// $$.setBasic(EbtInt, qual, $1.line);
+// }
+ | VEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(2);
+ }
+ | VEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(3);
+ }
+ | VEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(4);
+ }
+ | BVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, $1.line);
+ $$.setAggregate(2);
+ }
+ | BVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, $1.line);
+ $$.setAggregate(3);
+ }
+ | BVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtBool, qual, $1.line);
+ $$.setAggregate(4);
+ }
+ | IVEC2 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, $1.line);
+ $$.setAggregate(2);
+ }
+ | IVEC3 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, $1.line);
+ $$.setAggregate(3);
+ }
+ | IVEC4 {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtInt, qual, $1.line);
+ $$.setAggregate(4);
+ }
+ | MATRIX2 {
+ FRAG_VERT_ONLY("mat2", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(2, true);
+ }
+ | MATRIX3 {
+ FRAG_VERT_ONLY("mat3", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(3, true);
+ }
+ | MATRIX4 {
+ FRAG_VERT_ONLY("mat4", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtFloat, qual, $1.line);
+ $$.setAggregate(4, true);
+ }
+ | SAMPLER2D {
+ FRAG_VERT_ONLY("sampler2D", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSampler2D, qual, $1.line);
+ }
+ | SAMPLERCUBE {
+ FRAG_VERT_ONLY("samplerCube", $1.line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtSamplerCube, qual, $1.line);
+ }
+ | struct_specifier {
+ FRAG_VERT_ONLY("struct", $1.line);
+ $$ = $1;
+ $$.qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ }
+ | TYPE_NAME {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>($1.symbol)->getType();
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ $$.setBasic(EbtStruct, qual, $1.line);
+ $$.userDef = &structure;
+ }
+ ;
+
+struct_specifier
+ : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE {
+ if (context->reservedErrorCheck($2.line, *$2.string))
+ context->recover();
+
+ TType* structure = new TType($4, *$2.string);
+ TVariable* userTypeDef = new TVariable($2.string, *structure, true);
+ if (! context->symbolTable.insert(*userTypeDef)) {
+ context->error($2.line, "redefinition", $2.string->c_str(), "struct");
+ context->recover();
+ }
+ $$.setBasic(EbtStruct, EvqTemporary, $1.line);
+ $$.userDef = structure;
+ }
+ | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE {
+ TType* structure = new TType($3, TString(""));
+ $$.setBasic(EbtStruct, EvqTemporary, $1.line);
+ $$.userDef = structure;
+ }
+ ;
+
+struct_declaration_list
+ : struct_declaration {
+ $$ = $1;
+ }
+ | struct_declaration_list struct_declaration {
+ $$ = $1;
+ for (unsigned int i = 0; i < $2->size(); ++i) {
+ for (unsigned int j = 0; j < $$->size(); ++j) {
+ if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) {
+ context->error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str());
+ context->recover();
+ }
+ }
+ $$->push_back((*$2)[i]);
+ }
+ }
+ ;
+
+struct_declaration
+ : type_specifier struct_declarator_list SEMICOLON {
+ $$ = $2;
+
+ if (context->voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) {
+ context->recover();
+ }
+ for (unsigned int i = 0; i < $$->size(); ++i) {
+ //
+ // Careful not to replace already known aspects of type, like array-ness
+ //
+ TType* type = (*$$)[i].type;
+ type->setBasicType($1.type);
+ type->setNominalSize($1.size);
+ type->setMatrix($1.matrix);
+ type->setPrecision($1.precision);
+
+ // don't allow arrays of arrays
+ if (type->isArray()) {
+ if (context->arrayTypeErrorCheck($1.line, $1))
+ context->recover();
+ }
+ if ($1.array)
+ type->setArraySize($1.arraySize);
+ if ($1.userDef) {
+ type->setStruct($1.userDef->getStruct());
+ type->setTypeName($1.userDef->getTypeName());
+ }
+ }
+ }
+ ;
+
+struct_declarator_list
+ : struct_declarator {
+ $$ = NewPoolTTypeList();
+ $$->push_back($1);
+ }
+ | struct_declarator_list COMMA struct_declarator {
+ $$->push_back($3);
+ }
+ ;
+
+struct_declarator
+ : IDENTIFIER {
+ if (context->reservedErrorCheck($1.line, *$1.string))
+ context->recover();
+
+ $$.type = new TType(EbtVoid, EbpUndefined);
+ $$.line = $1.line;
+ $$.type->setFieldName(*$1.string);
+ }
+ | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET {
+ if (context->reservedErrorCheck($1.line, *$1.string))
+ context->recover();
+
+ $$.type = new TType(EbtVoid, EbpUndefined);
+ $$.line = $1.line;
+ $$.type->setFieldName(*$1.string);
+
+ int size;
+ if (context->arraySizeErrorCheck($2.line, $3, size))
+ context->recover();
+ $$.type->setArraySize(size);
+ }
+ ;
+
+initializer
+ : assignment_expression { $$ = $1; }
+ ;
+
+declaration_statement
+ : declaration { $$ = $1; }
+ ;
+
+statement
+ : compound_statement { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+// Grammar Note: No labeled statements; 'goto' is not supported.
+
+simple_statement
+ : declaration_statement { $$ = $1; }
+ | expression_statement { $$ = $1; }
+ | selection_statement { $$ = $1; }
+ | iteration_statement { $$ = $1; }
+ | jump_statement { $$ = $1; }
+ ;
+
+compound_statement
+ : LEFT_BRACE RIGHT_BRACE { $$ = 0; }
+ | LEFT_BRACE { context->symbolTable.push(); } statement_list { context->symbolTable.pop(); } RIGHT_BRACE {
+ if ($3 != 0) {
+ $3->setOp(EOpSequence);
+ $3->setEndLine($5.line);
+ }
+ $$ = $3;
+ }
+ ;
+
+statement_no_new_scope
+ : compound_statement_no_new_scope { $$ = $1; }
+ | simple_statement { $$ = $1; }
+ ;
+
+compound_statement_no_new_scope
+ // Statement that doesn't create a new scope, for selection_statement, iteration_statement
+ : LEFT_BRACE RIGHT_BRACE {
+ $$ = 0;
+ }
+ | LEFT_BRACE statement_list RIGHT_BRACE {
+ if ($2) {
+ $2->setOp(EOpSequence);
+ $2->setEndLine($3.line);
+ }
+ $$ = $2;
+ }
+ ;
+
+statement_list
+ : statement {
+ $$ = context->intermediate.makeAggregate($1, 0);
+ }
+ | statement_list statement {
+ $$ = context->intermediate.growAggregate($1, $2, 0);
+ }
+ ;
+
+expression_statement
+ : SEMICOLON { $$ = 0; }
+ | expression SEMICOLON { $$ = static_cast<TIntermNode*>($1); }
+ ;
+
+selection_statement
+ : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement {
+ if (context->boolErrorCheck($1.line, $3))
+ context->recover();
+ $$ = context->intermediate.addSelection($3, $5, $1.line);
+ }
+ ;
+
+selection_rest_statement
+ : statement ELSE statement {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ | statement {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ ;
+
+// Grammar Note: No 'switch'. Switch statements not supported.
+
+condition
+ // In 1996 c++ draft, conditions can include single declarations
+ : expression {
+ $$ = $1;
+ if (context->boolErrorCheck($1->getLine(), $1))
+ context->recover();
+ }
+ | fully_specified_type IDENTIFIER EQUAL initializer {
+ TIntermNode* intermNode;
+ if (context->structQualifierErrorCheck($2.line, $1))
+ context->recover();
+ if (context->boolErrorCheck($2.line, $1))
+ context->recover();
+
+ if (!context->executeInitializer($2.line, *$2.string, $1, $4, intermNode))
+ $$ = $4;
+ else {
+ context->recover();
+ $$ = 0;
+ }
+ }
+ ;
+
+iteration_statement
+ : WHILE LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopWhile, 0, $4, 0, $6, $1.line);
+ --context->loopNestingLevel;
+ }
+ | DO { ++context->loopNestingLevel; } statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON {
+ if (context->boolErrorCheck($8.line, $6))
+ context->recover();
+
+ $$ = context->intermediate.addLoop(ELoopDoWhile, 0, $6, 0, $3, $4.line);
+ --context->loopNestingLevel;
+ }
+ | FOR LEFT_PAREN { context->symbolTable.push(); ++context->loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope {
+ context->symbolTable.pop();
+ $$ = context->intermediate.addLoop(ELoopFor, $4, reinterpret_cast<TIntermTyped*>($5.node1), reinterpret_cast<TIntermTyped*>($5.node2), $7, $1.line);
+ --context->loopNestingLevel;
+ }
+ ;
+
+for_init_statement
+ : expression_statement {
+ $$ = $1;
+ }
+ | declaration_statement {
+ $$ = $1;
+ }
+ ;
+
+conditionopt
+ : condition {
+ $$ = $1;
+ }
+ | /* May be null */ {
+ $$ = 0;
+ }
+ ;
+
+for_rest_statement
+ : conditionopt SEMICOLON {
+ $$.node1 = $1;
+ $$.node2 = 0;
+ }
+ | conditionopt SEMICOLON expression {
+ $$.node1 = $1;
+ $$.node2 = $3;
+ }
+ ;
+
+jump_statement
+ : CONTINUE SEMICOLON {
+ if (context->loopNestingLevel <= 0) {
+ context->error($1.line, "continue statement only allowed in loops", "", "");
+ context->recover();
+ }
+ $$ = context->intermediate.addBranch(EOpContinue, $1.line);
+ }
+ | BREAK SEMICOLON {
+ if (context->loopNestingLevel <= 0) {
+ context->error($1.line, "break statement only allowed in loops", "", "");
+ context->recover();
+ }
+ $$ = context->intermediate.addBranch(EOpBreak, $1.line);
+ }
+ | RETURN SEMICOLON {
+ $$ = context->intermediate.addBranch(EOpReturn, $1.line);
+ if (context->currentFunctionType->getBasicType() != EbtVoid) {
+ context->error($1.line, "non-void function must return a value", "return", "");
+ context->recover();
+ }
+ }
+ | RETURN expression SEMICOLON {
+ $$ = context->intermediate.addBranch(EOpReturn, $2, $1.line);
+ context->functionReturnsValue = true;
+ if (context->currentFunctionType->getBasicType() == EbtVoid) {
+ context->error($1.line, "void function cannot return a value", "return", "");
+ context->recover();
+ } else if (*(context->currentFunctionType) != $2->getType()) {
+ context->error($1.line, "function return is not matching type:", "return", "");
+ context->recover();
+ }
+ }
+ | DISCARD SEMICOLON {
+ FRAG_ONLY("discard", $1.line);
+ $$ = context->intermediate.addBranch(EOpKill, $1.line);
+ }
+ ;
+
+// Grammar Note: No 'goto'. Gotos are not supported.
+
+translation_unit
+ : external_declaration {
+ $$ = $1;
+ context->treeRoot = $$;
+ }
+ | translation_unit external_declaration {
+ $$ = context->intermediate.growAggregate($1, $2, 0);
+ context->treeRoot = $$;
+ }
+ ;
+
+external_declaration
+ : function_definition {
+ $$ = $1;
+ }
+ | declaration {
+ $$ = $1;
+ }
+ ;
+
+function_definition
+ : function_prototype {
+ TFunction* function = $1.function;
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName()));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined()) {
+ //
+ // Then this function already has a body.
+ //
+ context->error($1.line, "function already has a body", function->getName().c_str(), "");
+ context->recover();
+ }
+ prevDec->setDefined();
+
+ //
+ // Raise error message if main function takes any parameters or return anything other than void
+ //
+ if (function->getName() == "main") {
+ if (function->getParamCount() > 0) {
+ context->error($1.line, "function cannot take any parameter(s)", function->getName().c_str(), "");
+ context->recover();
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid) {
+ context->error($1.line, "", function->getReturnType().getBasicString(), "main function cannot return a value");
+ context->recover();
+ }
+ }
+
+ //
+ // New symbol table scope for body of function plus its arguments
+ //
+ context->symbolTable.push();
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ context->currentFunctionType = &(prevDec->getReturnType());
+ context->functionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate* paramNodes = new TIntermAggregate;
+ for (int i = 0; i < function->getParamCount(); i++) {
+ const TParameter& param = function->getParam(i);
+ if (param.name != 0) {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (! context->symbolTable.insert(*variable)) {
+ context->error($1.line, "redefinition", variable->getName().c_str(), "");
+ context->recover();
+ delete variable;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ paramNodes = context->intermediate.growAggregate(
+ paramNodes,
+ context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(), $1.line),
+ $1.line);
+ } else {
+ paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, $1.line), $1.line);
+ }
+ }
+ context->intermediate.setAggregateOperator(paramNodes, EOpParameters, $1.line);
+ $1.intermAggregate = paramNodes;
+ context->loopNestingLevel = 0;
+ }
+ compound_statement_no_new_scope {
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ context->error($1.line, "function does not return a value:", "", $1.function->getName().c_str());
+ context->recover();
+ }
+ context->symbolTable.pop();
+ $$ = context->intermediate.growAggregate($1.intermAggregate, $3, 0);
+ context->intermediate.setAggregateOperator($$, EOpFunction, $1.line);
+ $$->getAsAggregate()->setName($1.function->getMangledName().c_str());
+ $$->getAsAggregate()->setType($1.function->getReturnType());
+
+ // store the pragma information for debug and optimize and other vendor specific
+ // information. This information can be queried from the parse tree
+ $$->getAsAggregate()->setOptimize(context->contextPragma.optimize);
+ $$->getAsAggregate()->setDebug(context->contextPragma.debug);
+ $$->getAsAggregate()->addToPragmaTable(context->contextPragma.pragmaTable);
+
+ if ($3 && $3->getAsAggregate())
+ $$->getAsAggregate()->setEndLine($3->getAsAggregate()->getEndLine());
+ }
+ ;
+
+%%
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context);
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang_lex.cpp b/Source/ThirdParty/ANGLE/src/compiler/glslang_lex.cpp
new file mode 100644
index 000000000..fa28d4162
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/glslang_lex.cpp
@@ -0,0 +1,3190 @@
+#line 17 "compiler/glslang.l"
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_glslang_lexer.sh. DO NOT EDIT!
+
+
+
+#line 13 "compiler/glslang_lex.cpp"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 35
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* An opaque pointer. */
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void* yyscan_t;
+#endif
+
+/* For convenience, these vars (plus the bison vars far below)
+ are macros in the reentrant scanner. */
+#define yyin yyg->yyin_r
+#define yyout yyg->yyout_r
+#define yyextra yyg->yyextra_r
+#define yyleng yyg->yyleng_r
+#define yytext yyg->yytext_r
+#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
+#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
+#define yy_flex_debug yyg->yy_flex_debug_r
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yyg->yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yyg->yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin ,yyscanner )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires
+ * access to the local variable yy_act. Since yyless() is a macro, it would break
+ * existing scanners that call yyless() from OUTSIDE yylex.
+ * One obvious solution it to make yy_act a global. I tried that, and saw
+ * a 5% performance hit in a non-yylineno scanner, because yy_act is
+ * normally declared as a register variable-- so it is not worth it.
+ */
+ #define YY_LESS_LINENO(n) \
+ do { \
+ int yyl;\
+ for ( yyl = n; yyl < yyleng; ++yyl )\
+ if ( yytext[yyl] == '\n' )\
+ --yylineno;\
+ }while(0)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = yyg->yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner )
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \
+ ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top]
+
+void yyrestart (FILE *input_file ,yyscan_t yyscanner );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ,yyscan_t yyscanner );
+void yy_delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yy_flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner );
+void yypop_buffer_state (yyscan_t yyscanner );
+
+static void yyensure_buffer_stack (yyscan_t yyscanner );
+static void yy_load_buffer_state (yyscan_t yyscanner );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ,yyscanner)
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
+
+void *yyalloc (yy_size_t ,yyscan_t yyscanner );
+void *yyrealloc (void *,yy_size_t ,yyscan_t yyscanner );
+void yyfree (void * ,yyscan_t yyscanner );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (yyscanner); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+#define yywrap(n) 1
+#define YY_SKIP_YYWRAP
+
+typedef unsigned char YY_CHAR;
+
+typedef int yy_state_type;
+
+#define yytext_ptr yytext_r
+
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
+static int yy_get_next_buffer (yyscan_t yyscanner );
+static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yyg->yytext_ptr = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ yyg->yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yyg->yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 145
+#define YY_END_OF_BUFFER 146
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[411] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 146, 144, 143, 143,
+ 128, 134, 139, 123, 124, 132, 131, 120, 129, 127,
+ 133, 92, 92, 121, 117, 135, 122, 136, 140, 88,
+ 125, 126, 138, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 118, 137, 119, 130, 3, 4, 3,
+ 142, 145, 141, 114, 100, 119, 108, 103, 98, 106,
+ 96, 107, 97, 95, 2, 1, 99, 94, 90, 91,
+ 0, 0, 92, 126, 118, 125, 115, 111, 113, 112,
+ 116, 88, 104, 110, 88, 88, 88, 88, 88, 88,
+
+ 88, 88, 88, 88, 17, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 20, 22,
+ 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 105, 109, 5, 141,
+ 0, 1, 94, 0, 0, 93, 89, 101, 102, 48,
+ 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 18, 88, 88,
+ 88, 88, 88, 88, 88, 88, 26, 88, 88, 88,
+ 88, 88, 88, 88, 88, 23, 88, 88, 88, 88,
+
+ 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 0, 95,
+ 0, 94, 88, 28, 88, 88, 85, 88, 88, 88,
+ 88, 88, 88, 88, 21, 51, 88, 88, 88, 88,
+ 88, 56, 70, 88, 88, 88, 88, 88, 88, 88,
+ 88, 67, 9, 33, 34, 35, 88, 88, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
+ 88, 54, 29, 88, 88, 88, 88, 88, 88, 36,
+ 37, 38, 27, 88, 88, 88, 15, 42, 43, 44,
+ 49, 12, 88, 88, 88, 88, 81, 82, 83, 88,
+
+ 30, 71, 25, 78, 79, 80, 7, 75, 76, 77,
+ 88, 24, 73, 88, 88, 39, 40, 41, 88, 88,
+ 88, 88, 88, 88, 88, 88, 88, 68, 88, 88,
+ 88, 88, 88, 88, 88, 50, 88, 87, 88, 88,
+ 19, 88, 88, 88, 88, 69, 64, 59, 88, 88,
+ 88, 88, 88, 74, 55, 88, 62, 32, 88, 84,
+ 63, 47, 57, 88, 88, 88, 88, 88, 88, 88,
+ 88, 58, 31, 88, 88, 88, 8, 88, 88, 88,
+ 88, 88, 52, 13, 88, 14, 88, 88, 16, 65,
+ 88, 88, 88, 60, 88, 88, 88, 53, 72, 61,
+
+ 11, 66, 6, 86, 10, 45, 88, 88, 46, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 1, 1, 1, 5, 6, 1, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 16, 16, 16, 20, 20, 21, 22, 23,
+ 24, 25, 26, 1, 27, 27, 28, 29, 30, 27,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 32, 31, 31,
+ 33, 1, 34, 35, 31, 1, 36, 37, 38, 39,
+
+ 40, 41, 42, 43, 44, 31, 45, 46, 47, 48,
+ 49, 50, 31, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[64] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 3, 3, 3, 3, 3, 3,
+ 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
+ 4, 4, 1, 1, 1, 3, 3, 3, 3, 3,
+ 3, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 1,
+ 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[416] =
+ { 0,
+ 0, 0, 61, 62, 71, 0, 606, 607, 607, 607,
+ 581, 42, 129, 607, 607, 580, 126, 607, 125, 123,
+ 137, 149, 157, 578, 607, 175, 578, 44, 607, 0,
+ 607, 607, 120, 95, 103, 142, 146, 136, 156, 552,
+ 168, 162, 551, 120, 158, 545, 173, 558, 172, 178,
+ 111, 186, 554, 607, 159, 607, 607, 607, 607, 582,
+ 607, 607, 0, 607, 607, 607, 607, 607, 607, 607,
+ 607, 607, 607, 222, 607, 0, 607, 228, 254, 262,
+ 281, 0, 290, 607, 607, 607, 571, 607, 607, 607,
+ 570, 0, 607, 607, 546, 539, 542, 550, 549, 536,
+
+ 551, 538, 544, 532, 529, 542, 529, 526, 526, 532,
+ 520, 527, 524, 534, 520, 526, 529, 530, 0, 204,
+ 529, 207, 515, 528, 519, 521, 511, 525, 522, 524,
+ 507, 512, 509, 498, 183, 512, 508, 510, 499, 502,
+ 212, 507, 499, 511, 186, 504, 607, 607, 607, 0,
+ 306, 0, 316, 332, 270, 342, 0, 607, 607, 0,
+ 496, 500, 509, 506, 490, 490, 161, 505, 502, 502,
+ 500, 497, 489, 495, 482, 493, 496, 0, 493, 481,
+ 488, 485, 489, 482, 471, 470, 483, 486, 483, 478,
+ 469, 294, 474, 477, 468, 465, 469, 475, 466, 457,
+
+ 460, 458, 468, 454, 452, 452, 454, 451, 462, 461,
+ 278, 456, 451, 440, 320, 458, 460, 449, 348, 354,
+ 360, 366, 450, 0, 448, 336, 0, 440, 438, 446,
+ 435, 452, 441, 370, 0, 0, 435, 445, 445, 430,
+ 373, 0, 0, 432, 376, 433, 427, 426, 427, 426,
+ 379, 0, 0, 0, 0, 0, 422, 423, 428, 419,
+ 432, 427, 426, 418, 422, 414, 417, 421, 426, 425,
+ 416, 0, 0, 422, 411, 411, 416, 415, 412, 0,
+ 0, 0, 0, 402, 414, 416, 0, 0, 0, 0,
+ 0, 0, 404, 405, 399, 409, 0, 0, 0, 400,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 407, 0, 0, 405, 401, 0, 0, 0, 397, 393,
+ 398, 388, 401, 387, 400, 389, 396, 0, 394, 396,
+ 380, 389, 395, 390, 378, 0, 380, 0, 379, 382,
+ 0, 371, 370, 370, 383, 0, 385, 0, 384, 383,
+ 368, 381, 368, 0, 0, 371, 0, 0, 363, 0,
+ 0, 0, 0, 360, 371, 364, 368, 303, 297, 288,
+ 300, 0, 0, 283, 290, 269, 0, 277, 274, 255,
+ 232, 255, 0, 0, 244, 0, 236, 226, 0, 0,
+ 225, 208, 211, 0, 185, 202, 131, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 134, 117, 0, 607,
+ 398, 400, 402, 406, 142
+ } ;
+
+static yyconst flex_int16_t yy_def[416] =
+ { 0,
+ 410, 1, 411, 411, 410, 5, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 412,
+ 410, 410, 410, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 413, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 414, 410, 410, 410, 410,
+ 410, 415, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 412, 410, 410, 412, 412, 412, 412, 412, 412,
+
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 410, 410, 410, 413,
+ 410, 414, 410, 410, 410, 410, 415, 410, 410, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 410, 410,
+ 410, 410, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 0,
+ 410, 410, 410, 410, 410
+ } ;
+
+static yyconst flex_int16_t yy_nxt[671] =
+ { 0,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 23, 23, 23, 23,
+ 24, 25, 26, 27, 28, 29, 30, 30, 30, 30,
+ 30, 30, 31, 32, 33, 34, 35, 36, 37, 38,
+ 39, 40, 41, 42, 30, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 30, 30, 30, 54,
+ 55, 56, 57, 59, 59, 65, 66, 90, 91, 60,
+ 60, 8, 61, 62, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 63, 63, 63,
+
+ 63, 63, 63, 8, 8, 8, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 8, 8, 8, 8, 67, 70, 72, 74, 74, 74,
+ 74, 74, 74, 93, 157, 75, 95, 96, 73, 71,
+ 76, 97, 68, 98, 94, 123, 409, 99, 141, 124,
+ 77, 78, 142, 79, 79, 79, 79, 79, 80, 78,
+ 408, 83, 83, 83, 83, 83, 83, 100, 81, 85,
+ 82, 107, 147, 108, 407, 103, 81, 101, 81, 104,
+ 102, 110, 109, 125, 105, 86, 81, 87, 88, 111,
+
+ 106, 112, 119, 116, 113, 82, 126, 132, 128, 120,
+ 114, 117, 229, 230, 133, 134, 121, 137, 204, 148,
+ 138, 143, 118, 129, 135, 144, 130, 136, 139, 216,
+ 406, 217, 405, 205, 145, 140, 74, 74, 74, 74,
+ 74, 74, 153, 153, 153, 153, 153, 153, 396, 184,
+ 404, 151, 185, 186, 190, 211, 187, 154, 188, 397,
+ 403, 151, 191, 212, 402, 401, 78, 154, 79, 79,
+ 79, 79, 79, 80, 78, 400, 80, 80, 80, 80,
+ 80, 80, 399, 81, 156, 156, 156, 156, 156, 156,
+ 155, 81, 155, 81, 398, 156, 156, 156, 156, 156,
+
+ 156, 81, 78, 395, 83, 83, 83, 83, 83, 83,
+ 254, 255, 256, 394, 393, 219, 392, 219, 275, 81,
+ 220, 220, 220, 220, 220, 220, 276, 391, 390, 81,
+ 153, 153, 153, 153, 153, 153, 280, 281, 282, 389,
+ 388, 221, 387, 221, 386, 154, 222, 222, 222, 222,
+ 222, 222, 288, 289, 290, 154, 156, 156, 156, 156,
+ 156, 156, 220, 220, 220, 220, 220, 220, 220, 220,
+ 220, 220, 220, 220, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 222, 222, 297, 298, 299, 304,
+ 305, 306, 308, 309, 310, 316, 317, 318, 58, 58,
+
+ 58, 58, 92, 92, 150, 150, 152, 385, 152, 152,
+ 384, 383, 382, 381, 380, 379, 378, 377, 376, 375,
+ 374, 373, 372, 371, 370, 369, 368, 367, 366, 365,
+ 364, 363, 362, 361, 360, 359, 358, 357, 356, 355,
+ 354, 353, 352, 351, 350, 349, 348, 347, 346, 345,
+ 344, 343, 342, 341, 340, 339, 338, 337, 336, 335,
+ 334, 333, 332, 331, 330, 329, 328, 327, 326, 325,
+ 324, 323, 322, 321, 320, 319, 315, 314, 313, 312,
+ 311, 307, 303, 302, 301, 300, 296, 295, 294, 293,
+ 292, 291, 287, 286, 285, 284, 283, 279, 278, 277,
+
+ 274, 273, 272, 271, 270, 269, 268, 267, 266, 265,
+ 264, 263, 262, 261, 260, 259, 258, 257, 253, 252,
+ 251, 250, 249, 248, 247, 246, 245, 244, 243, 242,
+ 241, 240, 239, 238, 237, 236, 235, 234, 233, 232,
+ 231, 228, 227, 226, 225, 224, 223, 218, 215, 214,
+ 213, 210, 209, 208, 207, 206, 203, 202, 201, 200,
+ 199, 198, 197, 196, 195, 194, 193, 192, 189, 183,
+ 182, 181, 180, 179, 178, 177, 176, 175, 174, 173,
+ 172, 171, 170, 169, 168, 167, 166, 165, 164, 163,
+ 162, 161, 160, 159, 158, 149, 146, 131, 127, 122,
+
+ 115, 89, 84, 69, 64, 410, 7, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410
+ } ;
+
+static yyconst flex_int16_t yy_chk[671] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 3, 4, 12, 12, 28, 28, 3,
+ 4, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 13, 17, 19, 20, 20, 20,
+ 20, 20, 20, 33, 415, 21, 34, 34, 19, 17,
+ 21, 35, 13, 35, 33, 44, 408, 35, 51, 44,
+ 21, 22, 51, 22, 22, 22, 22, 22, 22, 23,
+ 407, 23, 23, 23, 23, 23, 23, 36, 22, 26,
+ 22, 38, 55, 38, 397, 37, 23, 36, 22, 37,
+ 36, 39, 38, 45, 37, 26, 23, 26, 26, 39,
+
+ 37, 39, 42, 41, 39, 22, 45, 49, 47, 42,
+ 39, 41, 167, 167, 49, 49, 42, 50, 135, 55,
+ 50, 52, 41, 47, 49, 52, 47, 49, 50, 145,
+ 396, 145, 395, 135, 52, 50, 74, 74, 74, 74,
+ 74, 74, 78, 78, 78, 78, 78, 78, 381, 120,
+ 393, 74, 120, 120, 122, 141, 120, 78, 120, 381,
+ 392, 74, 122, 141, 391, 388, 79, 78, 79, 79,
+ 79, 79, 79, 79, 80, 387, 80, 80, 80, 80,
+ 80, 80, 385, 79, 155, 155, 155, 155, 155, 155,
+ 81, 80, 81, 79, 382, 81, 81, 81, 81, 81,
+
+ 81, 80, 83, 380, 83, 83, 83, 83, 83, 83,
+ 192, 192, 192, 379, 378, 151, 376, 151, 211, 83,
+ 151, 151, 151, 151, 151, 151, 211, 375, 374, 83,
+ 153, 153, 153, 153, 153, 153, 215, 215, 215, 371,
+ 370, 154, 369, 154, 368, 153, 154, 154, 154, 154,
+ 154, 154, 226, 226, 226, 153, 156, 156, 156, 156,
+ 156, 156, 219, 219, 219, 219, 219, 219, 220, 220,
+ 220, 220, 220, 220, 221, 221, 221, 221, 221, 221,
+ 222, 222, 222, 222, 222, 222, 234, 234, 234, 241,
+ 241, 241, 245, 245, 245, 251, 251, 251, 411, 411,
+
+ 411, 411, 412, 412, 413, 413, 414, 367, 414, 414,
+ 366, 365, 364, 359, 356, 353, 352, 351, 350, 349,
+ 347, 345, 344, 343, 342, 340, 339, 337, 335, 334,
+ 333, 332, 331, 330, 329, 327, 326, 325, 324, 323,
+ 322, 321, 320, 319, 315, 314, 311, 300, 296, 295,
+ 294, 293, 286, 285, 284, 279, 278, 277, 276, 275,
+ 274, 271, 270, 269, 268, 267, 266, 265, 264, 263,
+ 262, 261, 260, 259, 258, 257, 250, 249, 248, 247,
+ 246, 244, 240, 239, 238, 237, 233, 232, 231, 230,
+ 229, 228, 225, 223, 218, 217, 216, 214, 213, 212,
+
+ 210, 209, 208, 207, 206, 205, 204, 203, 202, 201,
+ 200, 199, 198, 197, 196, 195, 194, 193, 191, 190,
+ 189, 188, 187, 186, 185, 184, 183, 182, 181, 180,
+ 179, 177, 176, 175, 174, 173, 172, 171, 170, 169,
+ 168, 166, 165, 164, 163, 162, 161, 146, 144, 143,
+ 142, 140, 139, 138, 137, 136, 134, 133, 132, 131,
+ 130, 129, 128, 127, 126, 125, 124, 123, 121, 118,
+ 117, 116, 115, 114, 113, 112, 111, 110, 109, 108,
+ 107, 106, 105, 104, 103, 102, 101, 100, 99, 98,
+ 97, 96, 95, 91, 87, 60, 53, 48, 46, 43,
+
+ 40, 27, 24, 16, 11, 7, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410,
+ 410, 410, 410, 410, 410, 410, 410, 410, 410, 410
+ } ;
+
+/* Table of booleans, true if rule could match eol. */
+static yyconst flex_int32_t yy_rule_can_match_eol[146] =
+ { 0,
+0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, };
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+/*
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+This file contains the Lex specification for GLSL ES.
+Based on ANSI C grammar, Lex specification:
+http://www.lysator.liu.se/c/ANSI-C-grammar-l.html
+
+IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_glslang_lexer.sh,
+WHICH GENERATES THE GLSL ES LEXER (glslang_lex.cpp).
+*/
+
+#include "compiler/glslang.h"
+#include "compiler/ParseHelper.h"
+#include "compiler/util.h"
+#include "glslang_tab.h"
+
+/* windows only pragma */
+#ifdef _MSC_VER
+#pragma warning(disable : 4102)
+#endif
+
+#define YY_USER_ACTION yylval->lex.line = yylineno;
+#define YY_INPUT(buf, result, max_size) \
+ result = string_input(buf, max_size, yyscanner);
+
+static int string_input(char* buf, int max_size, yyscan_t yyscanner);
+static int check_type(yyscan_t yyscanner);
+static int reserved_word(yyscan_t yyscanner);
+
+#define INITIAL 0
+#define COMMENT 1
+#define FIELDS 2
+
+#define YY_EXTRA_TYPE TParseContext*
+
+/* Holds the entire state of the reentrant scanner. */
+struct yyguts_t
+ {
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+ YYSTYPE * yylval_r;
+
+ }; /* end struct yyguts_t */
+
+static int yy_init_globals (yyscan_t yyscanner );
+
+ /* This must go here because YYSTYPE and YYLTYPE are included
+ * from bison output in section 1.*/
+ # define yylval yyg->yylval_r
+
+int yylex_init (yyscan_t* scanner);
+
+int yylex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner);
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (yyscan_t yyscanner );
+
+int yyget_debug (yyscan_t yyscanner );
+
+void yyset_debug (int debug_flag ,yyscan_t yyscanner );
+
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner );
+
+FILE *yyget_in (yyscan_t yyscanner );
+
+void yyset_in (FILE * in_str ,yyscan_t yyscanner );
+
+FILE *yyget_out (yyscan_t yyscanner );
+
+void yyset_out (FILE * out_str ,yyscan_t yyscanner );
+
+int yyget_leng (yyscan_t yyscanner );
+
+char *yyget_text (yyscan_t yyscanner );
+
+int yyget_lineno (yyscan_t yyscanner );
+
+void yyset_lineno (int line_number ,yyscan_t yyscanner );
+
+int yyget_column (yyscan_t yyscanner );
+
+void yyset_column (int column_no ,yyscan_t yyscanner );
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner );
+
+void yyset_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (yyscan_t yyscanner );
+#else
+extern int yywrap (yyscan_t yyscanner );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner);
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner);
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (yyscan_t yyscanner );
+#else
+static int input (yyscan_t yyscanner );
+#endif
+
+#endif
+
+ static void yy_push_state (int new_state ,yyscan_t yyscanner);
+
+ static void yy_pop_state (yyscan_t yyscanner );
+
+ static int yy_top_state (yyscan_t yyscanner );
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ unsigned n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner)
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex \
+ (YYSTYPE * yylval_param ,yyscan_t yyscanner);
+
+#define YY_DECL int yylex \
+ (YYSTYPE * yylval_param , yyscan_t yyscanner)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ TParseContext* context = yyextra;
+
+ /* Single-line comments */
+
+ yylval = yylval_param;
+
+ if ( !yyg->yy_init )
+ {
+ yyg->yy_init = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yyg->yy_start )
+ yyg->yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ yy_load_buffer_state(yyscanner );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yyg->yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yyg->yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yyg->yy_start;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 411 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 410 );
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+
+ if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] )
+ {
+ int yyl;
+ for ( yyl = 0; yyl < yyleng; ++yyl )
+ if ( yytext[yyl] == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+ }
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yyg->yy_hold_char;
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+;
+ YY_BREAK
+/* Multi-line comments */
+case 2:
+YY_RULE_SETUP
+{ yy_push_state(COMMENT, yyscanner); }
+ YY_BREAK
+case 3:
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+;
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+{ yy_pop_state(yyscanner); }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+{ return(INVARIANT); }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+{ return(HIGH_PRECISION); }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+{ return(MEDIUM_PRECISION); }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+{ return(LOW_PRECISION); }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+{ return(PRECISION); }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+{ return(ATTRIBUTE); }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+{ return(CONST_QUAL); }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+{ return(UNIFORM); }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+{ return(VARYING); }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+{ return(BREAK); }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+{ return(CONTINUE); }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+{ return(DO); }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+{ return(FOR); }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+{ return(WHILE); }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+{ return(IF); }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+{ return(ELSE); }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+{ return(IN_QUAL); }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+{ return(OUT_QUAL); }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+{ return(INOUT_QUAL); }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return(FLOAT_TYPE); }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return(INT_TYPE); }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return(VOID_TYPE); }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return(BOOL_TYPE); }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+{ yylval->lex.b = true; return(BOOLCONSTANT); }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+{ yylval->lex.b = false; return(BOOLCONSTANT); }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+{ return(DISCARD); }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+{ return(RETURN); }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return(MATRIX2); }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return(MATRIX3); }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return(MATRIX4); }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (VEC2); }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (VEC3); }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (VEC4); }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (IVEC2); }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (IVEC3); }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (IVEC4); }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (BVEC2); }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (BVEC3); }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return (BVEC4); }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return SAMPLER2D; }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return SAMPLERCUBE; }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+{ context->lexAfterType = true; return(STRUCT); }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+{ return reserved_word(yyscanner); }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+{
+ yylval->lex.string = NewPoolTString(yytext);
+ return check_type(yyscanner);
+}
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+{ yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+{ yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+{ context->error(yylineno, "Invalid Octal number.", yytext, "", ""); context->recover(); return 0;}
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+{ yylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+{ yylval->lex.f = static_cast<float>(atof_dot(yytext)); return(FLOATCONSTANT); }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+{ return(ADD_ASSIGN); }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+{ return(SUB_ASSIGN); }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+{ return(MUL_ASSIGN); }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+{ return(DIV_ASSIGN); }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+{ return(MOD_ASSIGN); }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+{ return(LEFT_ASSIGN); }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+{ return(RIGHT_ASSIGN); }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+{ return(AND_ASSIGN); }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+{ return(XOR_ASSIGN); }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+{ return(OR_ASSIGN); }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+{ return(INC_OP); }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+{ return(DEC_OP); }
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+{ return(AND_OP); }
+ YY_BREAK
+case 109:
+YY_RULE_SETUP
+{ return(OR_OP); }
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+{ return(XOR_OP); }
+ YY_BREAK
+case 111:
+YY_RULE_SETUP
+{ return(LE_OP); }
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+{ return(GE_OP); }
+ YY_BREAK
+case 113:
+YY_RULE_SETUP
+{ return(EQ_OP); }
+ YY_BREAK
+case 114:
+YY_RULE_SETUP
+{ return(NE_OP); }
+ YY_BREAK
+case 115:
+YY_RULE_SETUP
+{ return(LEFT_OP); }
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+{ return(RIGHT_OP); }
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+{ context->lexAfterType = false; return(SEMICOLON); }
+ YY_BREAK
+case 118:
+YY_RULE_SETUP
+{ context->lexAfterType = false; return(LEFT_BRACE); }
+ YY_BREAK
+case 119:
+YY_RULE_SETUP
+{ return(RIGHT_BRACE); }
+ YY_BREAK
+case 120:
+YY_RULE_SETUP
+{ if (context->inTypeParen) context->lexAfterType = false; return(COMMA); }
+ YY_BREAK
+case 121:
+YY_RULE_SETUP
+{ return(COLON); }
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+{ context->lexAfterType = false; return(EQUAL); }
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+{ context->lexAfterType = false; context->inTypeParen = true; return(LEFT_PAREN); }
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+{ context->inTypeParen = false; return(RIGHT_PAREN); }
+ YY_BREAK
+case 125:
+YY_RULE_SETUP
+{ return(LEFT_BRACKET); }
+ YY_BREAK
+case 126:
+YY_RULE_SETUP
+{ return(RIGHT_BRACKET); }
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+{ BEGIN(FIELDS); return(DOT); }
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+{ return(BANG); }
+ YY_BREAK
+case 129:
+YY_RULE_SETUP
+{ return(DASH); }
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+{ return(TILDE); }
+ YY_BREAK
+case 131:
+YY_RULE_SETUP
+{ return(PLUS); }
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+{ return(STAR); }
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+{ return(SLASH); }
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+{ return(PERCENT); }
+ YY_BREAK
+case 135:
+YY_RULE_SETUP
+{ return(LEFT_ANGLE); }
+ YY_BREAK
+case 136:
+YY_RULE_SETUP
+{ return(RIGHT_ANGLE); }
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+{ return(VERTICAL_BAR); }
+ YY_BREAK
+case 138:
+YY_RULE_SETUP
+{ return(CARET); }
+ YY_BREAK
+case 139:
+YY_RULE_SETUP
+{ return(AMPERSAND); }
+ YY_BREAK
+case 140:
+YY_RULE_SETUP
+{ return(QUESTION); }
+ YY_BREAK
+case 141:
+YY_RULE_SETUP
+{
+ BEGIN(INITIAL);
+ yylval->lex.string = NewPoolTString(yytext);
+ return FIELD_SELECTION;
+}
+ YY_BREAK
+case 142:
+YY_RULE_SETUP
+{}
+ YY_BREAK
+case 143:
+/* rule 143 can match eol */
+YY_RULE_SETUP
+{ }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(COMMENT):
+case YY_STATE_EOF(FIELDS):
+{ context->AfterEOF = true; yyterminate(); }
+ YY_BREAK
+case 144:
+YY_RULE_SETUP
+{ context->warning(yylineno, "Unknown char", yytext, ""); return 0; }
+ YY_BREAK
+case 145:
+YY_RULE_SETUP
+ECHO;
+ YY_BREAK
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yyg->yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner);
+
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yyg->yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yyg->yy_last_accepting_cpos;
+ yy_current_state = yyg->yy_last_accepting_state;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yyg->yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap(yyscanner ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p =
+ yyg->yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yyg->yy_c_buf_p =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
+
+ yy_current_state = yy_get_previous_state( yyscanner );
+
+ yy_cp = yyg->yy_c_buf_p;
+ yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = yyg->yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+
+ int yy_c_buf_p_offset =
+ (int) (yyg->yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ yyg->yy_n_chars, (size_t) num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ if ( yyg->yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin ,yyscanner);
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ yyg->yy_n_chars += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_current_state = yyg->yy_start;
+
+ for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 411 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+{
+ register int yy_is_jam;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ register char *yy_cp = yyg->yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yyg->yy_last_accepting_state = yy_current_state;
+ yyg->yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 411 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 410);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (yyscan_t yyscanner)
+#else
+ static int input (yyscan_t yyscanner)
+#endif
+
+{
+ int c;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+
+ if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] )
+ /* This was really a NUL. */
+ *yyg->yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yyg->yy_c_buf_p - yyg->yytext_ptr;
+ ++yyg->yy_c_buf_p;
+
+ switch ( yy_get_next_buffer( yyscanner ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin ,yyscanner);
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap(yyscanner ) )
+ return EOF;
+
+ if ( ! yyg->yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput(yyscanner);
+#else
+ return input(yyscanner);
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yyg->yy_c_buf_p = yyg->yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */
+ *yyg->yy_c_buf_p = '\0'; /* preserve yytext */
+ yyg->yy_hold_char = *++yyg->yy_c_buf_p;
+
+ if ( c == '\n' )
+
+ do{ yylineno++;
+ yycolumn=0;
+ }while(0)
+;
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ * @param yyscanner The scanner object.
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack (yyscanner);
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
+ yy_load_buffer_state(yyscanner );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ * @param yyscanner The scanner object.
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack (yyscanner);
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state(yyscanner );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+static void yy_load_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ yyg->yy_hold_char = *yyg->yy_c_buf_p;
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ * @param yyscanner The scanner object.
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ,yyscanner );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file ,yyscanner);
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ * @param yyscanner The scanner object.
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf ,yyscanner );
+
+ yyfree((void *) b ,yyscanner );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+
+{
+ int oerrno = errno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ yy_flush_buffer(b ,yyscanner);
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ * @param yyscanner The scanner object.
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state(yyscanner );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ * @param yyscanner The scanner object.
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack(yyscanner);
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *yyg->yy_c_buf_p = yyg->yy_hold_char;
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p;
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ yyg->yy_buffer_stack_top++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ * @param yyscanner The scanner object.
+ */
+void yypop_buffer_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner);
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if (yyg->yy_buffer_stack_top > 0)
+ --yyg->yy_buffer_stack_top;
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state(yyscanner );
+ yyg->yy_did_buffer_switch_on_eof = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (yyscan_t yyscanner)
+{
+ int num_to_alloc;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (!yyg->yy_buffer_stack) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ yyg->yy_buffer_stack_top = 0;
+ return;
+ }
+
+ if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ yyg->yy_buffer_stack = (struct yy_buffer_state**)yyrealloc
+ (yyg->yy_buffer_stack,
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ , yyscanner);
+ if ( ! yyg->yy_buffer_stack )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*));
+ yyg->yy_buffer_stack_max = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ,yyscanner );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b ,yyscanner );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr , yyscan_t yyscanner)
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param bytes the byte buffer to scan
+ * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yyscanner The scanner object.
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner)
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n ,yyscanner );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n ,yyscanner);
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+ static void yy_push_state (int new_state , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( yyg->yy_start_stack_ptr >= yyg->yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yyg->yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yyg->yy_start_stack_depth * sizeof( int );
+
+ if ( ! yyg->yy_start_stack )
+ yyg->yy_start_stack = (int *) yyalloc(new_size ,yyscanner );
+
+ else
+ yyg->yy_start_stack = (int *) yyrealloc((void *) yyg->yy_start_stack,new_size ,yyscanner );
+
+ if ( ! yyg->yy_start_stack )
+ YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
+ }
+
+ yyg->yy_start_stack[yyg->yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+}
+
+ static void yy_pop_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ if ( --yyg->yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yyg->yy_start_stack[yyg->yy_start_stack_ptr]);
+}
+
+ static int yy_top_state (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyg->yy_start_stack[yyg->yy_start_stack_ptr - 1];
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner)
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = yyg->yy_hold_char; \
+ yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
+ yyg->yy_hold_char = *yyg->yy_c_buf_p; \
+ *yyg->yy_c_buf_p = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the user-defined data for this scanner.
+ * @param yyscanner The scanner object.
+ */
+YY_EXTRA_TYPE yyget_extra (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
+}
+
+/** Get the current line number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_lineno (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
+}
+
+/** Get the current column number.
+ * @param yyscanner The scanner object.
+ */
+int yyget_column (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
+}
+
+/** Get the input stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_in (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
+}
+
+/** Get the output stream.
+ * @param yyscanner The scanner object.
+ */
+FILE *yyget_out (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
+}
+
+/** Get the length of the current token.
+ * @param yyscanner The scanner object.
+ */
+int yyget_leng (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
+}
+
+/** Get the current token.
+ * @param yyscanner The scanner object.
+ */
+
+char *yyget_text (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
+}
+
+/** Set the user-defined data. This data is never touched by the scanner.
+ * @param user_defined The data to be associated with this scanner.
+ * @param yyscanner The scanner object.
+ */
+void yyset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
+}
+
+/** Set the current line number.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void yyset_lineno (int line_number , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "yyset_lineno called with no buffer" , yyscanner);
+
+ yylineno = line_number;
+}
+
+/** Set the current column.
+ * @param line_number
+ * @param yyscanner The scanner object.
+ */
+void yyset_column (int column_no , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "yyset_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ * @param yyscanner The scanner object.
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
+}
+
+int yyget_debug (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
+}
+
+/* Accessor methods for yylval and yylloc */
+
+YYSTYPE * yyget_lval (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yylval;
+}
+
+void yyset_lval (YYSTYPE * yylval_param , yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yylval = yylval_param;
+}
+
+/* User-visible API */
+
+/* yylex_init is special because it creates the scanner itself, so it is
+ * the ONLY reentrant function that doesn't take the scanner as the last argument.
+ * That's why we explicitly handle the declaration, instead of using our macros.
+ */
+
+int yylex_init(yyscan_t* ptr_yy_globals)
+
+{
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), NULL );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+/* yylex_init_extra has the same functionality as yylex_init, but follows the
+ * convention of taking the scanner as the last argument. Note however, that
+ * this is a *pointer* to a scanner, as it will be allocated by this call (and
+ * is the reason, too, why this function also must handle its own declaration).
+ * The user defined value in the first argument will be available to yyalloc in
+ * the yyextra field.
+ */
+
+int yylex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
+
+{
+ struct yyguts_t dummy_yyguts;
+
+ yyset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) yyalloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ yyset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
+}
+
+static int yy_init_globals (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (yyscan_t yyscanner)
+{
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state(yyscanner);
+ }
+
+ /* Destroy the stack itself. */
+ yyfree(yyg->yy_buffer_stack ,yyscanner);
+ yyg->yy_buffer_stack = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
+
+ /* Destroy the main struct (reentrant only). */
+ yyfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner)
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner)
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size , yyscan_t yyscanner)
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size , yyscan_t yyscanner)
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr , yyscan_t yyscanner)
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+extern "C" {
+// Preprocessor interface.
+#include "compiler/preprocessor/preprocess.h"
+
+#define SETUP_CONTEXT(pp) \
+ TParseContext* context = (TParseContext*) pp->pC; \
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+
+// Preprocessor callbacks.
+void CPPDebugLogMsg(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->infoSink.debug.message(EPrefixNone, msg);
+}
+
+void CPPWarningToInfoLog(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->warning(yylineno, msg, "", "");
+}
+
+void CPPShInfoLogMsg(const char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->error(yylineno, msg, "", "");
+ context->recover();
+}
+
+void CPPErrorToInfoLog(char *msg)
+{
+ SETUP_CONTEXT(cpp);
+ context->error(yylineno, msg, "", "");
+ context->recover();
+}
+
+void SetLineNumber(int line)
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0;
+ DecodeSourceLoc(yylineno, &string, NULL);
+ yylineno = EncodeSourceLoc(string, line);
+}
+
+void SetStringNumber(int string)
+{
+ SETUP_CONTEXT(cpp);
+ int line = 0;
+ DecodeSourceLoc(yylineno, NULL, &line);
+ yylineno = EncodeSourceLoc(string, line);
+}
+
+int GetStringNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0;
+ DecodeSourceLoc(yylineno, &string, NULL);
+ return string;
+}
+
+int GetLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int line = 0;
+ DecodeSourceLoc(yylineno, NULL, &line);
+ return line;
+}
+
+void IncLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0, line = 0;
+ DecodeSourceLoc(yylineno, &string, &line);
+ yylineno = EncodeSourceLoc(string, ++line);
+}
+
+void DecLineNumber()
+{
+ SETUP_CONTEXT(cpp);
+ int string = 0, line = 0;
+ DecodeSourceLoc(yylineno, &string, &line);
+ yylineno = EncodeSourceLoc(string, --line);
+}
+
+void HandlePragma(const char **tokens, int numTokens)
+{
+ SETUP_CONTEXT(cpp);
+ if (!strcmp(tokens[0], "optimize")) {
+ if (numTokens != 4) {
+ CPPShInfoLogMsg("optimize pragma syntax is incorrect");
+ return;
+ }
+
+ if (strcmp(tokens[1], "(")) {
+ CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword");
+ return;
+ }
+
+ if (!strcmp(tokens[2], "on"))
+ context->contextPragma.optimize = true;
+ else if (!strcmp(tokens[2], "off"))
+ context->contextPragma.optimize = false;
+ else {
+ CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma");
+ return;
+ }
+
+ if (strcmp(tokens[3], ")")) {
+ CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma");
+ return;
+ }
+ } else if (!strcmp(tokens[0], "debug")) {
+ if (numTokens != 4) {
+ CPPShInfoLogMsg("debug pragma syntax is incorrect");
+ return;
+ }
+
+ if (strcmp(tokens[1], "(")) {
+ CPPShInfoLogMsg("\"(\" expected after 'debug' keyword");
+ return;
+ }
+
+ if (!strcmp(tokens[2], "on"))
+ context->contextPragma.debug = true;
+ else if (!strcmp(tokens[2], "off"))
+ context->contextPragma.debug = false;
+ else {
+ CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma");
+ return;
+ }
+
+ if (strcmp(tokens[3], ")")) {
+ CPPShInfoLogMsg("\")\" expected to end 'debug' pragma");
+ return;
+ }
+ } else {
+#ifdef PRAGMA_TABLE
+ //
+ // implementation specific pragma
+ // use ((TParseContext *)cpp->pC)->contextPragma.pragmaTable to store the information about pragma
+ // For now, just ignore the pragma that the implementation cannot recognize
+ // An Example of one such implementation for a pragma that has a syntax like
+ // #pragma pragmaname(pragmavalue)
+ // This implementation stores the current pragmavalue against the pragma name in pragmaTable.
+ //
+ if (numTokens == 4 && !strcmp(tokens[1], "(") && !strcmp(tokens[3], ")")) {
+ TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable;
+ TPragmaTable::iterator iter;
+ iter = pragmaTable.find(TString(tokens[0]));
+ if (iter != pragmaTable.end()) {
+ iter->second = tokens[2];
+ } else {
+ pragmaTable[ tokens[0] ] = tokens[2];
+ }
+ } else if (numTokens >= 2) {
+ TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable;
+ TPragmaTable::iterator iter;
+ iter = pragmaTable.find(TString(tokens[0]));
+ if (iter != pragmaTable.end()) {
+ iter->second = tokens[1];
+ } else {
+ pragmaTable[ tokens[0] ] = tokens[1];
+ }
+ }
+#endif // PRAGMA_TABLE
+ }
+}
+
+void StoreStr(char *string)
+{
+ SETUP_CONTEXT(cpp);
+ TString strSrc;
+ strSrc = TString(string);
+
+ context->HashErrMsg = context->HashErrMsg + " " + strSrc;
+}
+
+const char* GetStrfromTStr(void)
+{
+ SETUP_CONTEXT(cpp);
+ cpp->ErrMsg = context->HashErrMsg.c_str();
+ return cpp->ErrMsg;
+}
+
+void ResetTString(void)
+{
+ SETUP_CONTEXT(cpp);
+ context->HashErrMsg = "";
+}
+
+TBehavior GetBehavior(const char* behavior)
+{
+ if (!strcmp("require", behavior))
+ return EBhRequire;
+ else if (!strcmp("enable", behavior))
+ return EBhEnable;
+ else if (!strcmp("disable", behavior))
+ return EBhDisable;
+ else if (!strcmp("warn", behavior))
+ return EBhWarn;
+ else {
+ CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str());
+ return EBhDisable;
+ }
+}
+
+void updateExtensionBehavior(const char* extName, const char* behavior)
+{
+ SETUP_CONTEXT(cpp);
+ TBehavior behaviorVal = GetBehavior(behavior);
+ TMap<TString, TBehavior>:: iterator iter;
+ TString msg;
+
+ // special cased for all extension
+ if (!strcmp(extName, "all")) {
+ if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) {
+ CPPShInfoLogMsg("extension 'all' cannot have 'require' or 'enable' behavior");
+ return;
+ } else {
+ for (iter = context->extensionBehavior.begin(); iter != context->extensionBehavior.end(); ++iter)
+ iter->second = behaviorVal;
+ }
+ } else {
+ iter = context->extensionBehavior.find(TString(extName));
+ if (iter == context->extensionBehavior.end()) {
+ switch (behaviorVal) {
+ case EBhRequire:
+ CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str());
+ break;
+ case EBhEnable:
+ case EBhWarn:
+ case EBhDisable:
+ msg = TString("extension '") + extName + "' is not supported";
+ context->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno);
+ break;
+ }
+ return;
+ } else
+ iter->second = behaviorVal;
+ }
+}
+} // extern "C"
+
+int string_input(char* buf, int max_size, yyscan_t yyscanner) {
+ int len;
+
+ if ((len = yylex_CPP(buf, max_size)) == 0)
+ return 0;
+ if (len >= max_size)
+ YY_FATAL_ERROR("input buffer overflow, can't enlarge buffer because scanner uses REJECT");
+
+ buf[len] = ' ';
+ return len+1;
+}
+
+int check_type(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ int token = IDENTIFIER;
+ TSymbol* symbol = yyextra->symbolTable.find(yytext);
+ if (yyextra->lexAfterType == false && symbol && symbol->isVariable()) {
+ TVariable* variable = static_cast<TVariable*>(symbol);
+ if (variable->isUserType()) {
+ yyextra->lexAfterType = true;
+ token = TYPE_NAME;
+ }
+ }
+ yylval->lex.symbol = symbol;
+ return token;
+}
+
+int reserved_word(yyscan_t yyscanner) {
+ struct yyguts_t* yyg = (struct yyguts_t*) yyscanner;
+
+ yyextra->error(yylineno, "Illegal use of reserved word", yytext, "");
+ yyextra->recover();
+ return 0;
+}
+
+void yyerror(TParseContext* context, const char* reason) {
+ struct yyguts_t* yyg = (struct yyguts_t*) context->scanner;
+
+ if (context->AfterEOF) {
+ context->error(yylineno, reason, "unexpected EOF", "");
+ } else {
+ context->error(yylineno, reason, yytext, "");
+ }
+ context->recover();
+}
+
+int glslang_initialize(TParseContext* context) {
+ yyscan_t scanner = NULL;
+ if (yylex_init_extra(context,&scanner))
+ return 1;
+
+ context->scanner = scanner;
+ return 0;
+}
+
+int glslang_finalize(TParseContext* context) {
+ yyscan_t scanner = context->scanner;
+ if (scanner == NULL) return 0;
+
+ context->scanner = NULL;
+ return yylex_destroy(scanner);
+}
+
+void glslang_scan(int count, const char* const string[], const int length[],
+ TParseContext* context) {
+ yyrestart(NULL,context->scanner);
+ yyset_lineno(EncodeSourceLoc(0, 1),context->scanner);
+ context->AfterEOF = false;
+
+ // Init preprocessor.
+ cpp->pC = context;
+ cpp->PaWhichStr = 0;
+ cpp->PaArgv = string;
+ cpp->PaArgc = count;
+ cpp->PaStrLen = length;
+ cpp->pastFirstStatement = 0;
+ ScanFromString(string[0]);
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang_tab.cpp b/Source/ThirdParty/ANGLE/src/compiler/glslang_tab.cpp
new file mode 100644
index 000000000..47ca2ee61
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/glslang_tab.cpp
@@ -0,0 +1,4716 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton implementation for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 1
+
+/* Using locations. */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INVARIANT = 258,
+ HIGH_PRECISION = 259,
+ MEDIUM_PRECISION = 260,
+ LOW_PRECISION = 261,
+ PRECISION = 262,
+ ATTRIBUTE = 263,
+ CONST_QUAL = 264,
+ BOOL_TYPE = 265,
+ FLOAT_TYPE = 266,
+ INT_TYPE = 267,
+ BREAK = 268,
+ CONTINUE = 269,
+ DO = 270,
+ ELSE = 271,
+ FOR = 272,
+ IF = 273,
+ DISCARD = 274,
+ RETURN = 275,
+ BVEC2 = 276,
+ BVEC3 = 277,
+ BVEC4 = 278,
+ IVEC2 = 279,
+ IVEC3 = 280,
+ IVEC4 = 281,
+ VEC2 = 282,
+ VEC3 = 283,
+ VEC4 = 284,
+ MATRIX2 = 285,
+ MATRIX3 = 286,
+ MATRIX4 = 287,
+ IN_QUAL = 288,
+ OUT_QUAL = 289,
+ INOUT_QUAL = 290,
+ UNIFORM = 291,
+ VARYING = 292,
+ STRUCT = 293,
+ VOID_TYPE = 294,
+ WHILE = 295,
+ SAMPLER2D = 296,
+ SAMPLERCUBE = 297,
+ IDENTIFIER = 298,
+ TYPE_NAME = 299,
+ FLOATCONSTANT = 300,
+ INTCONSTANT = 301,
+ BOOLCONSTANT = 302,
+ FIELD_SELECTION = 303,
+ LEFT_OP = 304,
+ RIGHT_OP = 305,
+ INC_OP = 306,
+ DEC_OP = 307,
+ LE_OP = 308,
+ GE_OP = 309,
+ EQ_OP = 310,
+ NE_OP = 311,
+ AND_OP = 312,
+ OR_OP = 313,
+ XOR_OP = 314,
+ MUL_ASSIGN = 315,
+ DIV_ASSIGN = 316,
+ ADD_ASSIGN = 317,
+ MOD_ASSIGN = 318,
+ LEFT_ASSIGN = 319,
+ RIGHT_ASSIGN = 320,
+ AND_ASSIGN = 321,
+ XOR_ASSIGN = 322,
+ OR_ASSIGN = 323,
+ SUB_ASSIGN = 324,
+ LEFT_PAREN = 325,
+ RIGHT_PAREN = 326,
+ LEFT_BRACKET = 327,
+ RIGHT_BRACKET = 328,
+ LEFT_BRACE = 329,
+ RIGHT_BRACE = 330,
+ DOT = 331,
+ COMMA = 332,
+ COLON = 333,
+ EQUAL = 334,
+ SEMICOLON = 335,
+ BANG = 336,
+ DASH = 337,
+ TILDE = 338,
+ PLUS = 339,
+ STAR = 340,
+ SLASH = 341,
+ PERCENT = 342,
+ LEFT_ANGLE = 343,
+ RIGHT_ANGLE = 344,
+ VERTICAL_BAR = 345,
+ CARET = 346,
+ AMPERSAND = 347,
+ QUESTION = 348
+ };
+#endif
+/* Tokens. */
+#define INVARIANT 258
+#define HIGH_PRECISION 259
+#define MEDIUM_PRECISION 260
+#define LOW_PRECISION 261
+#define PRECISION 262
+#define ATTRIBUTE 263
+#define CONST_QUAL 264
+#define BOOL_TYPE 265
+#define FLOAT_TYPE 266
+#define INT_TYPE 267
+#define BREAK 268
+#define CONTINUE 269
+#define DO 270
+#define ELSE 271
+#define FOR 272
+#define IF 273
+#define DISCARD 274
+#define RETURN 275
+#define BVEC2 276
+#define BVEC3 277
+#define BVEC4 278
+#define IVEC2 279
+#define IVEC3 280
+#define IVEC4 281
+#define VEC2 282
+#define VEC3 283
+#define VEC4 284
+#define MATRIX2 285
+#define MATRIX3 286
+#define MATRIX4 287
+#define IN_QUAL 288
+#define OUT_QUAL 289
+#define INOUT_QUAL 290
+#define UNIFORM 291
+#define VARYING 292
+#define STRUCT 293
+#define VOID_TYPE 294
+#define WHILE 295
+#define SAMPLER2D 296
+#define SAMPLERCUBE 297
+#define IDENTIFIER 298
+#define TYPE_NAME 299
+#define FLOATCONSTANT 300
+#define INTCONSTANT 301
+#define BOOLCONSTANT 302
+#define FIELD_SELECTION 303
+#define LEFT_OP 304
+#define RIGHT_OP 305
+#define INC_OP 306
+#define DEC_OP 307
+#define LE_OP 308
+#define GE_OP 309
+#define EQ_OP 310
+#define NE_OP 311
+#define AND_OP 312
+#define OR_OP 313
+#define XOR_OP 314
+#define MUL_ASSIGN 315
+#define DIV_ASSIGN 316
+#define ADD_ASSIGN 317
+#define MOD_ASSIGN 318
+#define LEFT_ASSIGN 319
+#define RIGHT_ASSIGN 320
+#define AND_ASSIGN 321
+#define XOR_ASSIGN 322
+#define OR_ASSIGN 323
+#define SUB_ASSIGN 324
+#define LEFT_PAREN 325
+#define RIGHT_PAREN 326
+#define LEFT_BRACKET 327
+#define RIGHT_BRACKET 328
+#define LEFT_BRACE 329
+#define RIGHT_BRACE 330
+#define DOT 331
+#define COMMA 332
+#define COLON 333
+#define EQUAL 334
+#define SEMICOLON 335
+#define BANG 336
+#define DASH 337
+#define TILDE 338
+#define PLUS 339
+#define STAR 340
+#define SLASH 341
+#define PERCENT 342
+#define LEFT_ANGLE 343
+#define RIGHT_ANGLE 344
+#define VERTICAL_BAR 345
+#define CARET 346
+#define AMPERSAND 347
+#define QUESTION 348
+
+
+
+
+/* Copy the first part of user declarations. */
+
+
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// This file is auto-generated by generate_glslang_parser.sh. DO NOT EDIT!
+
+#include "compiler/SymbolTable.h"
+#include "compiler/ParseHelper.h"
+#include "GLSLANG/ShaderLang.h"
+
+#define YYLEX_PARAM context->scanner
+
+
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* Enabling the token table. */
+#ifndef YYTOKEN_TABLE
+# define YYTOKEN_TABLE 0
+#endif
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+
+{
+ struct {
+ TSourceLoc line;
+ union {
+ TString *string;
+ float f;
+ int i;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TSourceLoc line;
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TTypeLine typeLine;
+ TTypeList* typeList;
+ };
+ } interm;
+}
+/* Line 193 of yacc.c. */
+
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations. */
+
+
+extern int yylex(YYSTYPE* yylval_param, void* yyscanner);
+extern void yyerror(TParseContext* context, const char* reason);
+
+#define FRAG_VERT_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER && \
+ context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex/fragment shaders only ", S, "", ""); \
+ context->recover(); \
+ } \
+}
+
+#define VERTEX_ONLY(S, L) { \
+ if (context->shaderType != SH_VERTEX_SHADER) { \
+ context->error(L, " supported in vertex shaders only ", S, "", ""); \
+ context->recover(); \
+ } \
+}
+
+#define FRAG_ONLY(S, L) { \
+ if (context->shaderType != SH_FRAGMENT_SHADER) { \
+ context->error(L, " supported in fragment shaders only ", S, "", ""); \
+ context->recover(); \
+ } \
+}
+
+
+/* Line 216 of yacc.c. */
+
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+ int i;
+#endif
+{
+ return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined _STDLIB_H \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef _STDLIB_H
+# define _STDLIB_H 1
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss;
+ YYSTYPE yyvs;
+ };
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(To, From, Count) \
+ __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+# else
+# define YYCOPY(To, From, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (To)[yyi] = (From)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack, Stack, yysize); \
+ Stack = &yyptr->Stack; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 69
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 1362
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 94
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 78
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 193
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 296
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 348
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 5, 7, 9, 11, 13, 17, 19,
+ 24, 26, 30, 33, 36, 38, 40, 42, 46, 49,
+ 52, 55, 57, 60, 64, 67, 69, 71, 73, 75,
+ 78, 81, 84, 86, 88, 90, 92, 96, 100, 102,
+ 106, 110, 112, 114, 118, 122, 126, 130, 132, 136,
+ 140, 142, 144, 146, 148, 152, 154, 158, 160, 164,
+ 166, 172, 174, 178, 180, 182, 184, 186, 188, 190,
+ 194, 196, 199, 202, 207, 210, 212, 214, 217, 221,
+ 225, 228, 234, 238, 241, 245, 248, 249, 251, 253,
+ 255, 257, 259, 263, 269, 276, 282, 284, 287, 292,
+ 298, 303, 306, 308, 311, 313, 315, 317, 320, 322,
+ 324, 327, 329, 331, 333, 335, 340, 342, 344, 346,
+ 348, 350, 352, 354, 356, 358, 360, 362, 364, 366,
+ 368, 370, 372, 374, 376, 378, 380, 386, 391, 393,
+ 396, 400, 402, 406, 408, 413, 415, 417, 419, 421,
+ 423, 425, 427, 429, 431, 434, 435, 436, 442, 444,
+ 446, 449, 453, 455, 458, 460, 463, 469, 473, 475,
+ 477, 482, 483, 490, 491, 500, 501, 509, 511, 513,
+ 515, 516, 519, 523, 526, 529, 532, 536, 539, 541,
+ 544, 546, 548, 549
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 168, 0, -1, 43, -1, 95, -1, 46, -1, 45,
+ -1, 47, -1, 70, 122, 71, -1, 96, -1, 97,
+ 72, 98, 73, -1, 99, -1, 97, 76, 48, -1,
+ 97, 51, -1, 97, 52, -1, 122, -1, 100, -1,
+ 101, -1, 97, 76, 101, -1, 103, 71, -1, 102,
+ 71, -1, 104, 39, -1, 104, -1, 104, 120, -1,
+ 103, 77, 120, -1, 105, 70, -1, 140, -1, 43,
+ -1, 48, -1, 97, -1, 51, 106, -1, 52, 106,
+ -1, 107, 106, -1, 84, -1, 82, -1, 81, -1,
+ 106, -1, 108, 85, 106, -1, 108, 86, 106, -1,
+ 108, -1, 109, 84, 108, -1, 109, 82, 108, -1,
+ 109, -1, 110, -1, 111, 88, 110, -1, 111, 89,
+ 110, -1, 111, 53, 110, -1, 111, 54, 110, -1,
+ 111, -1, 112, 55, 111, -1, 112, 56, 111, -1,
+ 112, -1, 113, -1, 114, -1, 115, -1, 116, 57,
+ 115, -1, 116, -1, 117, 59, 116, -1, 117, -1,
+ 118, 58, 117, -1, 118, -1, 118, 93, 122, 78,
+ 120, -1, 119, -1, 106, 121, 120, -1, 79, -1,
+ 60, -1, 61, -1, 62, -1, 69, -1, 120, -1,
+ 122, 77, 120, -1, 119, -1, 125, 80, -1, 133,
+ 80, -1, 7, 138, 139, 80, -1, 126, 71, -1,
+ 128, -1, 127, -1, 128, 130, -1, 127, 77, 130,
+ -1, 135, 43, 70, -1, 137, 43, -1, 137, 43,
+ 72, 123, 73, -1, 136, 131, 129, -1, 131, 129,
+ -1, 136, 131, 132, -1, 131, 132, -1, -1, 33,
+ -1, 34, -1, 35, -1, 137, -1, 134, -1, 133,
+ 77, 43, -1, 133, 77, 43, 72, 73, -1, 133,
+ 77, 43, 72, 123, 73, -1, 133, 77, 43, 79,
+ 146, -1, 135, -1, 135, 43, -1, 135, 43, 72,
+ 73, -1, 135, 43, 72, 123, 73, -1, 135, 43,
+ 79, 146, -1, 3, 43, -1, 137, -1, 136, 137,
+ -1, 9, -1, 8, -1, 37, -1, 3, 37, -1,
+ 36, -1, 139, -1, 138, 139, -1, 4, -1, 5,
+ -1, 6, -1, 140, -1, 140, 72, 123, 73, -1,
+ 39, -1, 11, -1, 12, -1, 10, -1, 27, -1,
+ 28, -1, 29, -1, 21, -1, 22, -1, 23, -1,
+ 24, -1, 25, -1, 26, -1, 30, -1, 31, -1,
+ 32, -1, 41, -1, 42, -1, 141, -1, 44, -1,
+ 38, 43, 74, 142, 75, -1, 38, 74, 142, 75,
+ -1, 143, -1, 142, 143, -1, 137, 144, 80, -1,
+ 145, -1, 144, 77, 145, -1, 43, -1, 43, 72,
+ 123, 73, -1, 120, -1, 124, -1, 150, -1, 149,
+ -1, 147, -1, 156, -1, 157, -1, 160, -1, 167,
+ -1, 74, 75, -1, -1, -1, 74, 151, 155, 152,
+ 75, -1, 154, -1, 149, -1, 74, 75, -1, 74,
+ 155, 75, -1, 148, -1, 155, 148, -1, 80, -1,
+ 122, 80, -1, 18, 70, 122, 71, 158, -1, 148,
+ 16, 148, -1, 148, -1, 122, -1, 135, 43, 79,
+ 146, -1, -1, 40, 70, 161, 159, 71, 153, -1,
+ -1, 15, 162, 148, 40, 70, 122, 71, 80, -1,
+ -1, 17, 70, 163, 164, 166, 71, 153, -1, 156,
+ -1, 147, -1, 159, -1, -1, 165, 80, -1, 165,
+ 80, 122, -1, 14, 80, -1, 13, 80, -1, 20,
+ 80, -1, 20, 122, 80, -1, 19, 80, -1, 169,
+ -1, 168, 169, -1, 170, -1, 124, -1, -1, 125,
+ 171, 154, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 153, 153, 188, 191, 204, 209, 214, 220, 223,
+ 296, 299, 408, 418, 431, 439, 538, 541, 549, 553,
+ 560, 564, 571, 577, 586, 594, 649, 656, 666, 669,
+ 679, 689, 710, 711, 712, 717, 718, 727, 739, 740,
+ 748, 759, 763, 764, 774, 784, 794, 807, 808, 818,
+ 831, 835, 839, 843, 844, 857, 858, 871, 872, 885,
+ 886, 903, 904, 917, 918, 919, 920, 921, 925, 928,
+ 939, 947, 972, 977, 984, 1020, 1023, 1030, 1038, 1059,
+ 1078, 1089, 1118, 1123, 1133, 1138, 1148, 1151, 1154, 1157,
+ 1163, 1170, 1173, 1189, 1207, 1231, 1254, 1258, 1276, 1284,
+ 1316, 1336, 1412, 1421, 1444, 1447, 1453, 1461, 1469, 1477,
+ 1487, 1494, 1497, 1500, 1506, 1509, 1524, 1528, 1532, 1536,
+ 1545, 1550, 1555, 1560, 1565, 1570, 1575, 1580, 1585, 1590,
+ 1596, 1602, 1608, 1613, 1618, 1623, 1636, 1649, 1657, 1660,
+ 1675, 1707, 1711, 1717, 1725, 1741, 1745, 1749, 1750, 1756,
+ 1757, 1758, 1759, 1760, 1764, 1765, 1765, 1765, 1775, 1776,
+ 1781, 1784, 1794, 1797, 1803, 1804, 1808, 1816, 1820, 1830,
+ 1835, 1852, 1852, 1857, 1857, 1864, 1864, 1872, 1875, 1881,
+ 1884, 1890, 1894, 1901, 1908, 1915, 1922, 1933, 1942, 1946,
+ 1953, 1956, 1962, 1962
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "INVARIANT", "HIGH_PRECISION",
+ "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "ATTRIBUTE",
+ "CONST_QUAL", "BOOL_TYPE", "FLOAT_TYPE", "INT_TYPE", "BREAK", "CONTINUE",
+ "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN", "BVEC2", "BVEC3",
+ "BVEC4", "IVEC2", "IVEC3", "IVEC4", "VEC2", "VEC3", "VEC4", "MATRIX2",
+ "MATRIX3", "MATRIX4", "IN_QUAL", "OUT_QUAL", "INOUT_QUAL", "UNIFORM",
+ "VARYING", "STRUCT", "VOID_TYPE", "WHILE", "SAMPLER2D", "SAMPLERCUBE",
+ "IDENTIFIER", "TYPE_NAME", "FLOATCONSTANT", "INTCONSTANT",
+ "BOOLCONSTANT", "FIELD_SELECTION", "LEFT_OP", "RIGHT_OP", "INC_OP",
+ "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP",
+ "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN",
+ "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN",
+ "SUB_ASSIGN", "LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACKET",
+ "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT", "COMMA", "COLON",
+ "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", "STAR", "SLASH",
+ "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", "CARET",
+ "AMPERSAND", "QUESTION", "$accept", "variable_identifier",
+ "primary_expression", "postfix_expression", "integer_expression",
+ "function_call", "function_call_or_method", "function_call_generic",
+ "function_call_header_no_parameters",
+ "function_call_header_with_parameters", "function_call_header",
+ "function_identifier", "unary_expression", "unary_operator",
+ "multiplicative_expression", "additive_expression", "shift_expression",
+ "relational_expression", "equality_expression", "and_expression",
+ "exclusive_or_expression", "inclusive_or_expression",
+ "logical_and_expression", "logical_xor_expression",
+ "logical_or_expression", "conditional_expression",
+ "assignment_expression", "assignment_operator", "expression",
+ "constant_expression", "declaration", "function_prototype",
+ "function_declarator", "function_header_with_parameters",
+ "function_header", "parameter_declarator", "parameter_declaration",
+ "parameter_qualifier", "parameter_type_specifier",
+ "init_declarator_list", "single_declaration", "fully_specified_type",
+ "type_qualifier", "type_specifier", "precision_qualifier",
+ "type_specifier_no_prec", "type_specifier_nonarray", "struct_specifier",
+ "struct_declaration_list", "struct_declaration",
+ "struct_declarator_list", "struct_declarator", "initializer",
+ "declaration_statement", "statement", "simple_statement",
+ "compound_statement", "@1", "@2", "statement_no_new_scope",
+ "compound_statement_no_new_scope", "statement_list",
+ "expression_statement", "selection_statement",
+ "selection_rest_statement", "condition", "iteration_statement", "@3",
+ "@4", "@5", "for_init_statement", "conditionopt", "for_rest_statement",
+ "jump_statement", "translation_unit", "external_declaration",
+ "function_definition", "@6", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 94, 95, 96, 96, 96, 96, 96, 97, 97,
+ 97, 97, 97, 97, 98, 99, 100, 100, 101, 101,
+ 102, 102, 103, 103, 104, 105, 105, 105, 106, 106,
+ 106, 106, 107, 107, 107, 108, 108, 108, 109, 109,
+ 109, 110, 111, 111, 111, 111, 111, 112, 112, 112,
+ 113, 114, 115, 116, 116, 117, 117, 118, 118, 119,
+ 119, 120, 120, 121, 121, 121, 121, 121, 122, 122,
+ 123, 124, 124, 124, 125, 126, 126, 127, 127, 128,
+ 129, 129, 130, 130, 130, 130, 131, 131, 131, 131,
+ 132, 133, 133, 133, 133, 133, 134, 134, 134, 134,
+ 134, 134, 135, 135, 136, 136, 136, 136, 136, 137,
+ 137, 138, 138, 138, 139, 139, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 141, 141, 142, 142,
+ 143, 144, 144, 145, 145, 146, 147, 148, 148, 149,
+ 149, 149, 149, 149, 150, 151, 152, 150, 153, 153,
+ 154, 154, 155, 155, 156, 156, 157, 158, 158, 159,
+ 159, 161, 160, 162, 160, 163, 160, 164, 164, 165,
+ 165, 166, 166, 167, 167, 167, 167, 167, 168, 168,
+ 169, 169, 171, 170
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 1, 1, 1, 1, 1, 3, 1, 4,
+ 1, 3, 2, 2, 1, 1, 1, 3, 2, 2,
+ 2, 1, 2, 3, 2, 1, 1, 1, 1, 2,
+ 2, 2, 1, 1, 1, 1, 3, 3, 1, 3,
+ 3, 1, 1, 3, 3, 3, 3, 1, 3, 3,
+ 1, 1, 1, 1, 3, 1, 3, 1, 3, 1,
+ 5, 1, 3, 1, 1, 1, 1, 1, 1, 3,
+ 1, 2, 2, 4, 2, 1, 1, 2, 3, 3,
+ 2, 5, 3, 2, 3, 2, 0, 1, 1, 1,
+ 1, 1, 3, 5, 6, 5, 1, 2, 4, 5,
+ 4, 2, 1, 2, 1, 1, 1, 2, 1, 1,
+ 2, 1, 1, 1, 1, 4, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 5, 4, 1, 2,
+ 3, 1, 3, 1, 4, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 0, 0, 5, 1, 1,
+ 2, 3, 1, 2, 1, 2, 5, 3, 1, 1,
+ 4, 0, 6, 0, 8, 0, 7, 1, 1, 1,
+ 0, 2, 3, 2, 2, 2, 3, 2, 1, 2,
+ 1, 1, 0, 3
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+ STATE-NUM when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 0, 0, 111, 112, 113, 0, 105, 104, 119, 117,
+ 118, 123, 124, 125, 126, 127, 128, 120, 121, 122,
+ 129, 130, 131, 108, 106, 0, 116, 132, 133, 135,
+ 191, 192, 0, 76, 86, 0, 91, 96, 0, 102,
+ 0, 109, 114, 134, 0, 188, 190, 107, 101, 0,
+ 0, 0, 71, 0, 74, 86, 0, 87, 88, 89,
+ 77, 0, 86, 0, 72, 97, 103, 110, 0, 1,
+ 189, 0, 0, 0, 0, 138, 0, 193, 78, 83,
+ 85, 90, 0, 92, 79, 0, 0, 2, 5, 4,
+ 6, 27, 0, 0, 0, 34, 33, 32, 3, 8,
+ 28, 10, 15, 16, 0, 0, 21, 0, 35, 0,
+ 38, 41, 42, 47, 50, 51, 52, 53, 55, 57,
+ 59, 70, 0, 25, 73, 0, 143, 0, 141, 137,
+ 139, 0, 0, 173, 0, 0, 0, 0, 0, 155,
+ 160, 164, 35, 61, 68, 0, 146, 0, 114, 149,
+ 162, 148, 147, 0, 150, 151, 152, 153, 80, 82,
+ 84, 0, 0, 98, 0, 145, 100, 29, 30, 0,
+ 12, 13, 0, 0, 19, 18, 0, 20, 22, 24,
+ 31, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 115, 136, 0, 0, 140,
+ 184, 183, 0, 175, 0, 187, 185, 0, 171, 154,
+ 0, 64, 65, 66, 67, 63, 0, 0, 165, 161,
+ 163, 0, 93, 0, 95, 99, 7, 0, 14, 26,
+ 11, 17, 23, 36, 37, 40, 39, 45, 46, 43,
+ 44, 48, 49, 54, 56, 58, 0, 0, 142, 0,
+ 0, 0, 186, 0, 156, 62, 69, 0, 94, 9,
+ 0, 144, 0, 178, 177, 180, 0, 169, 0, 0,
+ 0, 81, 60, 0, 179, 0, 0, 168, 166, 0,
+ 0, 157, 0, 181, 0, 0, 0, 159, 172, 158,
+ 0, 182, 176, 167, 170, 174
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 98, 99, 100, 227, 101, 102, 103, 104, 105,
+ 106, 107, 142, 109, 110, 111, 112, 113, 114, 115,
+ 116, 117, 118, 119, 120, 143, 144, 216, 145, 122,
+ 146, 147, 32, 33, 34, 79, 60, 61, 80, 35,
+ 36, 37, 38, 39, 40, 41, 123, 43, 74, 75,
+ 127, 128, 166, 149, 150, 151, 152, 210, 270, 288,
+ 289, 153, 154, 155, 278, 269, 156, 253, 202, 250,
+ 265, 275, 276, 157, 44, 45, 46, 53
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -250
+static const yytype_int16 yypact[] =
+{
+ 1218, -13, -250, -250, -250, 137, -250, -250, -250, -250,
+ -250, -250, -250, -250, -250, -250, -250, -250, -250, -250,
+ -250, -250, -250, -250, -250, -28, -250, -250, -250, -250,
+ -250, -55, -38, -4, 33, -20, -250, 44, 1259, -250,
+ 1318, -250, 18, -250, 1176, -250, -250, -250, -250, 1318,
+ -22, 1259, -250, 29, -250, 85, 73, -250, -250, -250,
+ -250, 1259, 113, 70, -250, 13, -250, -250, 949, -250,
+ -250, 49, 1259, 90, 1080, -250, 283, -250, -250, -250,
+ -250, 101, 1259, -56, -250, 757, 949, 80, -250, -250,
+ -250, -250, 949, 949, 949, -250, -250, -250, -250, -250,
+ -33, -250, -250, -250, 81, -15, 1013, 92, -250, 949,
+ 52, -75, -250, -25, 40, -250, -250, -250, 106, 105,
+ -46, -250, 93, -250, -250, 1121, 95, 9, -250, -250,
+ -250, 88, 89, -250, 100, 102, 91, 821, 104, 103,
+ -250, -250, 66, -250, -250, 20, -250, -55, 79, -250,
+ -250, -250, -250, 365, -250, -250, -250, -250, 107, -250,
+ -250, 885, 949, -250, 109, -250, -250, -250, -250, -6,
+ -250, -250, 949, 1283, -250, -250, 949, 110, -250, -250,
+ -250, 949, 949, 949, 949, 949, 949, 949, 949, 949,
+ 949, 949, 949, 949, 949, -250, -250, 949, 90, -250,
+ -250, -250, 447, -250, 949, -250, -250, 34, -250, -250,
+ 447, -250, -250, -250, -250, -250, 949, 949, -250, -250,
+ -250, 949, -250, 111, -250, -250, -250, 112, 99, -250,
+ 116, -250, -250, -250, -250, 52, 52, -250, -250, -250,
+ -250, -25, -25, -250, 106, 105, 77, 114, -250, 125,
+ 611, 4, -250, 693, 447, -250, -250, 115, -250, -250,
+ 949, -250, 119, -250, -250, 693, 447, 99, 134, 122,
+ 108, -250, -250, 949, -250, 117, 123, 174, -250, 120,
+ 529, -250, 7, 949, 529, 447, 949, -250, -250, -250,
+ 118, 99, -250, -250, -250, -250
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int16 yypgoto[] =
+{
+ -250, -250, -250, -250, -250, -250, -250, 22, -250, -250,
+ -250, -250, 31, -250, -27, -250, -79, -30, -250, -250,
+ -250, 5, 8, 12, -250, -63, -85, -250, -92, -82,
+ 10, 11, -250, -250, -250, 121, 149, 144, 126, -250,
+ -250, -233, -21, -24, 202, -23, 0, -250, 139, -66,
+ -250, 27, -156, -41, -149, -249, -250, -250, -250, -58,
+ 176, 17, -19, -250, -250, -35, -250, -250, -250, -250,
+ -250, -250, -250, -250, -250, 188, -250, -250
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If zero, do what YYDEFACT says.
+ If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -117
+static const yytype_int16 yytable[] =
+{
+ 42, 165, 169, 164, 220, 121, 224, 183, 130, 184,
+ 30, 31, 193, 62, 66, 50, 161, 67, 170, 171,
+ 268, 178, 121, 162, 47, 52, 71, 73, 185, 186,
+ 48, 287, 268, 54, 62, 287, 56, 81, 42, 172,
+ 42, 6, 7, 173, 42, 207, 51, 194, 73, 42,
+ 73, 42, 72, 249, 30, 31, 175, 63, 81, 130,
+ 64, 42, 176, 187, 188, 226, 57, 58, 59, 23,
+ 24, 217, 42, 55, 42, 266, 148, 165, 290, 223,
+ 228, 217, 42, 84, 217, 85, 198, 65, 56, 199,
+ 68, 232, 86, 6, 7, 189, 190, 217, 121, 108,
+ 218, 73, 246, 76, -75, 220, 237, 238, 239, 240,
+ 47, 217, 251, 83, 252, 247, 108, 277, 57, 58,
+ 59, 23, 24, 167, 168, 42, 211, 212, 213, 124,
+ 294, 255, 256, 126, 121, 214, 293, 181, 182, 257,
+ 180, 2, 3, 4, 158, 215, 57, 58, 59, -25,
+ -26, 68, 174, 148, 217, 260, 235, 236, 121, 241,
+ 242, 267, 179, 191, 192, 262, 195, 197, 200, 201,
+ 203, 205, 204, 267, 208, 272, 217, 279, 209, 221,
+ -116, 282, 225, 281, 258, 259, -27, 261, 271, 273,
+ 285, 291, 108, 280, 284, 231, 243, 283, 295, 286,
+ 244, 165, 148, 159, 78, 245, 82, 49, 160, 263,
+ 148, 125, 233, 234, 108, 108, 108, 108, 108, 108,
+ 108, 108, 108, 108, 108, 248, 292, 254, 108, 77,
+ 274, 264, 70, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 148, 0, 108, 148, 148, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 148, 148, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 148, 0, 0, 0, 148, 148, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 131, 132, 133, 0,
+ 134, 135, 136, 137, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 0, 0, 0, 23,
+ 24, 25, 26, 138, 27, 28, 87, 29, 88, 89,
+ 90, 91, 0, 0, 92, 93, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 94, 0, 0, 0, 139, 140, 0,
+ 0, 0, 0, 141, 95, 96, 0, 97, 1, 2,
+ 3, 4, 5, 6, 7, 8, 9, 10, 131, 132,
+ 133, 0, 134, 135, 136, 137, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 0, 0,
+ 0, 23, 24, 25, 26, 138, 27, 28, 87, 29,
+ 88, 89, 90, 91, 0, 0, 92, 93, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 94, 0, 0, 0, 139,
+ 219, 0, 0, 0, 0, 141, 95, 96, 0, 97,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 131, 132, 133, 0, 134, 135, 136, 137, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 0, 0, 0, 23, 24, 25, 26, 138, 27, 28,
+ 87, 29, 88, 89, 90, 91, 0, 0, 92, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 94, 0, 0,
+ 0, 139, 0, 0, 0, 0, 0, 141, 95, 96,
+ 0, 97, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 131, 132, 133, 0, 134, 135, 136, 137,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 0, 0, 0, 23, 24, 25, 26, 138,
+ 27, 28, 87, 29, 88, 89, 90, 91, 0, 0,
+ 92, 93, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 94,
+ 0, 0, 0, 76, 0, 0, 0, 0, 0, 141,
+ 95, 96, 0, 97, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 0, 0, 0, 0, 0, 0,
+ 0, 0, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 0, 0, 0, 23, 24, 25,
+ 26, 0, 27, 28, 87, 29, 88, 89, 90, 91,
+ 0, 0, 92, 93, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 94, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 141, 95, 96, 0, 97, 56, 2, 3, 4,
+ 0, 6, 7, 8, 9, 10, 0, 0, 0, 0,
+ 0, 0, 0, 0, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 0, 0, 0, 23,
+ 24, 25, 26, 0, 27, 28, 87, 29, 88, 89,
+ 90, 91, 0, 0, 92, 93, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 94, 0, 0, 0, 8, 9, 10,
+ 0, 0, 0, 0, 95, 96, 0, 97, 11, 12,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 0, 0, 0, 0, 0, 25, 26, 0, 27, 28,
+ 87, 29, 88, 89, 90, 91, 0, 0, 92, 93,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 94, 0, 0,
+ 163, 8, 9, 10, 0, 0, 0, 0, 95, 96,
+ 0, 97, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 0, 0, 0, 0, 0, 25,
+ 26, 0, 27, 28, 87, 29, 88, 89, 90, 91,
+ 0, 0, 92, 93, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 94, 0, 0, 0, 8, 9, 10, 0, 0,
+ 0, 206, 95, 96, 0, 97, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 0, 0,
+ 0, 0, 0, 25, 26, 0, 27, 28, 87, 29,
+ 88, 89, 90, 91, 0, 0, 92, 93, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 94, 0, 0, 222, 8,
+ 9, 10, 0, 0, 0, 0, 95, 96, 0, 97,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 0, 0, 0, 0, 0, 25, 26, 0,
+ 27, 28, 87, 29, 88, 89, 90, 91, 0, 0,
+ 92, 93, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 94,
+ 0, 0, 0, 8, 9, 10, 0, 0, 0, 0,
+ 95, 96, 0, 97, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 0, 0, 0, 0,
+ 0, 25, 177, 0, 27, 28, 87, 29, 88, 89,
+ 90, 91, 0, 0, 92, 93, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 94, 2, 3, 4, 0, 0, 0,
+ 8, 9, 10, 0, 95, 96, 0, 97, 0, 0,
+ 0, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 0, 0, 0, 0, 0, 25, 26,
+ 0, 27, 28, 0, 29, 2, 3, 4, 0, 0,
+ 0, 8, 9, 10, 0, 0, 0, 0, 0, 0,
+ 0, 0, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 0, 129, 0, 0, 0, 25,
+ 26, 0, 27, 28, 0, 29, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 69, 0, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 10, 0,
+ 0, 0, 0, 0, 0, 0, 196, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 0,
+ 0, 0, 23, 24, 25, 26, 0, 27, 28, 0,
+ 29, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 0, 0, 0, 0, 0, 0, 0, 0, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 0, 0, 0, 23, 24, 25, 26, 0, 27,
+ 28, 0, 29, 2, 3, 4, 0, 0, 0, 8,
+ 9, 10, 0, 0, 0, 0, 0, 0, 0, 0,
+ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 0, 8, 9, 10, 0, 25, 26, 0,
+ 27, 28, 0, 29, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 0, 0, 0, 0,
+ 0, 25, 26, 0, 27, 28, 229, 29, 8, 9,
+ 10, 230, 0, 0, 0, 0, 0, 0, 0, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 0, 0, 0, 0, 0, 25, 26, 0, 27,
+ 28, 0, 29
+};
+
+static const yytype_int16 yycheck[] =
+{
+ 0, 86, 94, 85, 153, 68, 162, 82, 74, 84,
+ 0, 0, 58, 34, 38, 43, 72, 40, 51, 52,
+ 253, 106, 85, 79, 37, 80, 49, 51, 53, 54,
+ 43, 280, 265, 71, 55, 284, 3, 61, 38, 72,
+ 40, 8, 9, 76, 44, 137, 74, 93, 72, 49,
+ 74, 51, 74, 202, 44, 44, 71, 77, 82, 125,
+ 80, 61, 77, 88, 89, 71, 33, 34, 35, 36,
+ 37, 77, 72, 77, 74, 71, 76, 162, 71, 161,
+ 172, 77, 82, 70, 77, 72, 77, 43, 3, 80,
+ 72, 176, 79, 8, 9, 55, 56, 77, 161, 68,
+ 80, 125, 194, 74, 71, 254, 185, 186, 187, 188,
+ 37, 77, 204, 43, 80, 197, 85, 266, 33, 34,
+ 35, 36, 37, 92, 93, 125, 60, 61, 62, 80,
+ 286, 216, 217, 43, 197, 69, 285, 85, 86, 221,
+ 109, 4, 5, 6, 43, 79, 33, 34, 35, 70,
+ 70, 72, 71, 153, 77, 78, 183, 184, 221, 189,
+ 190, 253, 70, 57, 59, 40, 73, 72, 80, 80,
+ 70, 80, 70, 265, 70, 260, 77, 43, 75, 72,
+ 70, 273, 73, 75, 73, 73, 70, 73, 73, 70,
+ 16, 283, 161, 71, 71, 173, 191, 80, 80, 79,
+ 192, 286, 202, 82, 55, 193, 62, 5, 82, 250,
+ 210, 72, 181, 182, 183, 184, 185, 186, 187, 188,
+ 189, 190, 191, 192, 193, 198, 284, 210, 197, 53,
+ 265, 250, 44, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 250, -1, 221, 253, 254, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 265, 266, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 280, -1, -1, -1, 284, 285, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, -1,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, -1, -1, -1, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, -1, -1, 51, 52, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 70, -1, -1, -1, 74, 75, -1,
+ -1, -1, -1, 80, 81, 82, -1, 84, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, -1, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, -1, -1,
+ -1, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, -1, -1, 51, 52, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 70, -1, -1, -1, 74,
+ 75, -1, -1, -1, -1, 80, 81, 82, -1, 84,
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
+ 13, 14, 15, -1, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ -1, -1, -1, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, -1, -1, 51, 52,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 70, -1, -1,
+ -1, 74, -1, -1, -1, -1, -1, 80, 81, 82,
+ -1, 84, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, -1, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, -1, -1, -1, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, -1, -1,
+ 51, 52, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 70,
+ -1, -1, -1, 74, -1, -1, -1, -1, -1, 80,
+ 81, 82, -1, 84, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, -1, -1, -1, -1, -1, -1,
+ -1, -1, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, -1, -1, -1, 36, 37, 38,
+ 39, -1, 41, 42, 43, 44, 45, 46, 47, 48,
+ -1, -1, 51, 52, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 70, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 80, 81, 82, -1, 84, 3, 4, 5, 6,
+ -1, 8, 9, 10, 11, 12, -1, -1, -1, -1,
+ -1, -1, -1, -1, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, -1, -1, -1, 36,
+ 37, 38, 39, -1, 41, 42, 43, 44, 45, 46,
+ 47, 48, -1, -1, 51, 52, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 70, -1, -1, -1, 10, 11, 12,
+ -1, -1, -1, -1, 81, 82, -1, 84, 21, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ -1, -1, -1, -1, -1, 38, 39, -1, 41, 42,
+ 43, 44, 45, 46, 47, 48, -1, -1, 51, 52,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 70, -1, -1,
+ 73, 10, 11, 12, -1, -1, -1, -1, 81, 82,
+ -1, 84, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, -1, -1, -1, -1, -1, 38,
+ 39, -1, 41, 42, 43, 44, 45, 46, 47, 48,
+ -1, -1, 51, 52, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 70, -1, -1, -1, 10, 11, 12, -1, -1,
+ -1, 80, 81, 82, -1, 84, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, -1, -1,
+ -1, -1, -1, 38, 39, -1, 41, 42, 43, 44,
+ 45, 46, 47, 48, -1, -1, 51, 52, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 70, -1, -1, 73, 10,
+ 11, 12, -1, -1, -1, -1, 81, 82, -1, 84,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, -1, -1, -1, -1, -1, 38, 39, -1,
+ 41, 42, 43, 44, 45, 46, 47, 48, -1, -1,
+ 51, 52, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, 70,
+ -1, -1, -1, 10, 11, 12, -1, -1, -1, -1,
+ 81, 82, -1, 84, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, -1, -1, -1, -1,
+ -1, 38, 39, -1, 41, 42, 43, 44, 45, 46,
+ 47, 48, -1, -1, 51, 52, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 70, 4, 5, 6, -1, -1, -1,
+ 10, 11, 12, -1, 81, 82, -1, 84, -1, -1,
+ -1, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, -1, -1, -1, -1, -1, 38, 39,
+ -1, 41, 42, -1, 44, 4, 5, 6, -1, -1,
+ -1, 10, 11, 12, -1, -1, -1, -1, -1, -1,
+ -1, -1, 21, 22, 23, 24, 25, 26, 27, 28,
+ 29, 30, 31, 32, -1, 75, -1, -1, -1, 38,
+ 39, -1, 41, 42, -1, 44, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 0, -1, -1, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, -1,
+ -1, -1, -1, -1, -1, -1, 75, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32, -1,
+ -1, -1, 36, 37, 38, 39, -1, 41, 42, -1,
+ 44, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, -1, -1, -1, -1, -1, -1, -1, -1, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, -1, -1, -1, 36, 37, 38, 39, -1, 41,
+ 42, -1, 44, 4, 5, 6, -1, -1, -1, 10,
+ 11, 12, -1, -1, -1, -1, -1, -1, -1, -1,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, -1, 10, 11, 12, -1, 38, 39, -1,
+ 41, 42, -1, 44, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, -1, -1, -1, -1,
+ -1, 38, 39, -1, 41, 42, 43, 44, 10, 11,
+ 12, 48, -1, -1, -1, -1, -1, -1, -1, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, -1, -1, -1, -1, -1, 38, 39, -1, 41,
+ 42, -1, 44
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 36, 37, 38, 39, 41, 42, 44,
+ 124, 125, 126, 127, 128, 133, 134, 135, 136, 137,
+ 138, 139, 140, 141, 168, 169, 170, 37, 43, 138,
+ 43, 74, 80, 171, 71, 77, 3, 33, 34, 35,
+ 130, 131, 136, 77, 80, 43, 137, 139, 72, 0,
+ 169, 139, 74, 137, 142, 143, 74, 154, 130, 129,
+ 132, 137, 131, 43, 70, 72, 79, 43, 45, 46,
+ 47, 48, 51, 52, 70, 81, 82, 84, 95, 96,
+ 97, 99, 100, 101, 102, 103, 104, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 123, 140, 80, 142, 43, 144, 145, 75,
+ 143, 13, 14, 15, 17, 18, 19, 20, 40, 74,
+ 75, 80, 106, 119, 120, 122, 124, 125, 140, 147,
+ 148, 149, 150, 155, 156, 157, 160, 167, 43, 129,
+ 132, 72, 79, 73, 123, 120, 146, 106, 106, 122,
+ 51, 52, 72, 76, 71, 71, 77, 39, 120, 70,
+ 106, 85, 86, 82, 84, 53, 54, 88, 89, 55,
+ 56, 57, 59, 58, 93, 73, 75, 72, 77, 80,
+ 80, 80, 162, 70, 70, 80, 80, 122, 70, 75,
+ 151, 60, 61, 62, 69, 79, 121, 77, 80, 75,
+ 148, 72, 73, 123, 146, 73, 71, 98, 122, 43,
+ 48, 101, 120, 106, 106, 108, 108, 110, 110, 110,
+ 110, 111, 111, 115, 116, 117, 122, 123, 145, 148,
+ 163, 122, 80, 161, 155, 120, 120, 123, 73, 73,
+ 78, 73, 40, 147, 156, 164, 71, 122, 135, 159,
+ 152, 73, 120, 70, 159, 165, 166, 148, 158, 43,
+ 71, 75, 122, 80, 71, 16, 79, 149, 153, 154,
+ 71, 122, 153, 148, 146, 80
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. */
+
+#define YYFAIL goto yyerrlab
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY && yylen == 1) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ yytoken = YYTRANSLATE (yychar); \
+ YYPOPSTACK (1); \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (context, YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+
+/* YY_LOCATION_PRINT -- Print the location on the stream.
+ This macro was not mandated originally: define only if we know
+ we won't break user code: when these are the locations we know. */
+
+#ifndef YY_LOCATION_PRINT
+# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
+# define YY_LOCATION_PRINT(File, Loc) \
+ fprintf (File, "%d.%d-%d.%d", \
+ (Loc).first_line, (Loc).first_column, \
+ (Loc).last_line, (Loc).last_column)
+# else
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+# endif
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value, context); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, TParseContext* context)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep, context)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ TParseContext* context;
+#endif
+{
+ if (!yyvaluep)
+ return;
+ YYUSE (context);
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, TParseContext* context)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep, context)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+ TParseContext* context;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep, context);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+ yytype_int16 *bottom;
+ yytype_int16 *top;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; bottom <= top; ++bottom)
+ YYFPRINTF (stderr, " %d", *bottom);
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule, TParseContext* context)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule, context)
+ YYSTYPE *yyvsp;
+ int yyrule;
+ TParseContext* context;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ fprintf (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ , context);
+ fprintf (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule, context); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into YYRESULT an error message about the unexpected token
+ YYCHAR while in state YYSTATE. Return the number of bytes copied,
+ including the terminating null byte. If YYRESULT is null, do not
+ copy anything; just return the number of bytes that would be
+ copied. As a special case, return 0 if an ordinary "syntax error"
+ message will do. Return YYSIZE_MAXIMUM if overflow occurs during
+ size calculation. */
+static YYSIZE_T
+yysyntax_error (char *yyresult, int yystate, int yychar)
+{
+ int yyn = yypact[yystate];
+
+ if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
+ return 0;
+ else
+ {
+ int yytype = YYTRANSLATE (yychar);
+ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ int yysize_overflow = 0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ int yyx;
+
+# if 0
+ /* This is so xgettext sees the translatable formats that are
+ constructed on the fly. */
+ YY_("syntax error, unexpected %s");
+ YY_("syntax error, unexpected %s, expecting %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s");
+ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
+# endif
+ char *yyfmt;
+ char const *yyf;
+ static char const yyunexpected[] = "syntax error, unexpected %s";
+ static char const yyexpecting[] = ", expecting %s";
+ static char const yyor[] = " or %s";
+ char yyformat[sizeof yyunexpected
+ + sizeof yyexpecting - 1
+ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
+ * (sizeof yyor - 1))];
+ char const *yyprefix = yyexpecting;
+
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yycount = 1;
+
+ yyarg[0] = yytname[yytype];
+ yyfmt = yystpcpy (yyformat, yyunexpected);
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ yyformat[sizeof yyunexpected - 1] = '\0';
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+ yyfmt = yystpcpy (yyfmt, yyprefix);
+ yyprefix = yyor;
+ }
+
+ yyf = YY_(yyformat);
+ yysize1 = yysize + yystrlen (yyf);
+ yysize_overflow |= (yysize1 < yysize);
+ yysize = yysize1;
+
+ if (yysize_overflow)
+ return YYSIZE_MAXIMUM;
+
+ if (yyresult)
+ {
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ char *yyp = yyresult;
+ int yyi = 0;
+ while ((*yyp = *yyf) != '\0')
+ {
+ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyf += 2;
+ }
+ else
+ {
+ yyp++;
+ yyf++;
+ }
+ }
+ }
+ return yysize;
+ }
+}
+#endif /* YYERROR_VERBOSE */
+
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, TParseContext* context)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep, context)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+ TParseContext* context;
+#endif
+{
+ YYUSE (yyvaluep);
+ YYUSE (context);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes. */
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (TParseContext* context);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (TParseContext* context)
+#else
+int
+yyparse (context)
+ TParseContext* context;
+#endif
+#endif
+{
+ /* The look-ahead symbol. */
+int yychar;
+
+/* The semantic value of the look-ahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+ int yystate;
+ int yyn;
+ int yyresult;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+ /* Look-ahead token as an internal (translated) token number. */
+ int yytoken = 0;
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+ /* Three stacks and their tools:
+ `yyss': related to states,
+ `yyvs': related to semantic values,
+ `yyls': related to locations.
+
+ Refer to the stacks thru separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss = yyssa;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs = yyvsa;
+ YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ YYSIZE_T yystacksize = YYINITDEPTH;
+
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss);
+ YYSTACK_RELOCATE (yyvs);
+
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ look-ahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to look-ahead token. */
+ yyn = yypact[yystate];
+ if (yyn == YYPACT_NINF)
+ goto yydefault;
+
+ /* Not known => get a look-ahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yyn == 0 || yyn == YYTABLE_NINF)
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the look-ahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token unless it is eof. */
+ if (yychar != YYEOF)
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 2:
+
+ {
+ // The symbol table search was done in the lexical phase
+ const TSymbol* symbol = (yyvsp[(1) - (1)].lex).symbol;
+ const TVariable* variable;
+ if (symbol == 0) {
+ context->error((yyvsp[(1) - (1)].lex).line, "undeclared identifier", (yyvsp[(1) - (1)].lex).string->c_str(), "");
+ context->recover();
+ TType type(EbtFloat, EbpUndefined);
+ TVariable* fakeVariable = new TVariable((yyvsp[(1) - (1)].lex).string, type);
+ context->symbolTable.insert(*fakeVariable);
+ variable = fakeVariable;
+ } else {
+ // This identifier can only be a variable type symbol
+ if (! symbol->isVariable()) {
+ context->error((yyvsp[(1) - (1)].lex).line, "variable expected", (yyvsp[(1) - (1)].lex).string->c_str(), "");
+ context->recover();
+ }
+ variable = static_cast<const TVariable*>(symbol);
+ }
+
+ // don't delete $1.string, it's used by error recovery, and the pool
+ // pop will reclaim the memory
+
+ if (variable->getType().getQualifier() == EvqConst ) {
+ ConstantUnion* constArray = variable->getConstPointer();
+ TType t(variable->getType());
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(constArray, t, (yyvsp[(1) - (1)].lex).line);
+ } else
+ (yyval.interm.intermTypedNode) = context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(), (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 3:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 4:
+
+ {
+ //
+ // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders,
+ // check for overflow for constants
+ //
+ if (abs((yyvsp[(1) - (1)].lex).i) >= (1 << 16)) {
+ context->error((yyvsp[(1) - (1)].lex).line, " integer constant overflow", "", "");
+ context->recover();
+ }
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst((yyvsp[(1) - (1)].lex).i);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 5:
+
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst((yyvsp[(1) - (1)].lex).f);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 6:
+
+ {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst((yyvsp[(1) - (1)].lex).b);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 7:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (3)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 8:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 9:
+
+ {
+ if (!(yyvsp[(1) - (4)].interm.intermTypedNode)->isArray() && !(yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix() && !(yyvsp[(1) - (4)].interm.intermTypedNode)->isVector()) {
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode())
+ context->error((yyvsp[(2) - (4)].lex).line, " left of '[' is not of type array, matrix, or vector ", (yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode()->getSymbol().c_str(), "");
+ else
+ context->error((yyvsp[(2) - (4)].lex).line, " left of '[' is not of type array, matrix, or vector ", "expression", "");
+ context->recover();
+ }
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getQualifier() == EvqConst && (yyvsp[(3) - (4)].interm.intermTypedNode)->getQualifier() == EvqConst) {
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray()) { // constant folding for arrays
+ (yyval.interm.intermTypedNode) = context->addConstArrayNode((yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line);
+ } else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isVector()) { // constant folding for vectors
+ TVectorFields fields;
+ fields.num = 1;
+ fields.offsets[0] = (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array
+ (yyval.interm.intermTypedNode) = context->addConstVectorNode(fields, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line);
+ } else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix()) { // constant folding for matrices
+ (yyval.interm.intermTypedNode) = context->addConstMatrixNode((yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line);
+ }
+ } else {
+ if ((yyvsp[(3) - (4)].interm.intermTypedNode)->getQualifier() == EvqConst) {
+ if (((yyvsp[(1) - (4)].interm.intermTypedNode)->isVector() || (yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix()) && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getNominalSize() <= (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !(yyvsp[(1) - (4)].interm.intermTypedNode)->isArray() ) {
+ context->error((yyvsp[(2) - (4)].lex).line, "", "[", "field selection out of range '%d'", (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
+ context->recover();
+ } else {
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray()) {
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize() == 0) {
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getMaxArraySize() <= (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) {
+ if (context->arraySetMaxSize((yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getTypePointer(), (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, (yyvsp[(2) - (4)].lex).line))
+ context->recover();
+ } else {
+ if (context->arraySetMaxSize((yyvsp[(1) - (4)].interm.intermTypedNode)->getAsSymbolNode(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getTypePointer(), 0, false, (yyvsp[(2) - (4)].lex).line))
+ context->recover();
+ }
+ } else if ( (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize()) {
+ context->error((yyvsp[(2) - (4)].lex).line, "", "[", "array index out of range '%d'", (yyvsp[(3) - (4)].interm.intermTypedNode)->getAsConstantUnion()->getUnionArrayPointer()->getIConst());
+ context->recover();
+ }
+ }
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(3) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line);
+ }
+ } else {
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray() && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getArraySize() == 0) {
+ context->error((yyvsp[(2) - (4)].lex).line, "", "[", "array must be redeclared with a size before being indexed with a variable");
+ context->recover();
+ }
+
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexIndirect, (yyvsp[(1) - (4)].interm.intermTypedNode), (yyvsp[(3) - (4)].interm.intermTypedNode), (yyvsp[(2) - (4)].lex).line);
+ }
+ }
+ if ((yyval.interm.intermTypedNode) == 0) {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpHigh, EvqConst), (yyvsp[(2) - (4)].lex).line);
+ } else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isArray()) {
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getStruct())
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getStruct(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getTypeName()));
+ else
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqTemporary, (yyvsp[(1) - (4)].interm.intermTypedNode)->getNominalSize(), (yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix()));
+
+ if ((yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getQualifier() == EvqConst)
+ (yyval.interm.intermTypedNode)->getTypePointer()->setQualifier(EvqConst);
+ } else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix() && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getQualifier() == EvqConst)
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqConst, (yyvsp[(1) - (4)].interm.intermTypedNode)->getNominalSize()));
+ else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isMatrix())
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqTemporary, (yyvsp[(1) - (4)].interm.intermTypedNode)->getNominalSize()));
+ else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isVector() && (yyvsp[(1) - (4)].interm.intermTypedNode)->getType().getQualifier() == EvqConst)
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqConst));
+ else if ((yyvsp[(1) - (4)].interm.intermTypedNode)->isVector())
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (4)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (4)].interm.intermTypedNode)->getPrecision(), EvqTemporary));
+ else
+ (yyval.interm.intermTypedNode)->setType((yyvsp[(1) - (4)].interm.intermTypedNode)->getType());
+ ;}
+ break;
+
+ case 10:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 11:
+
+ {
+ if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isArray()) {
+ context->error((yyvsp[(3) - (3)].lex).line, "cannot apply dot operator to an array", ".", "");
+ context->recover();
+ }
+
+ if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isVector()) {
+ TVectorFields fields;
+ if (! context->parseVectorFields(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize(), fields, (yyvsp[(3) - (3)].lex).line)) {
+ fields.num = 1;
+ fields.offsets[0] = 0;
+ context->recover();
+ }
+
+ if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) { // constant folding for vector fields
+ (yyval.interm.intermTypedNode) = context->addConstVectorNode(fields, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].lex).line);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ else
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(), EvqConst, (int) (*(yyvsp[(3) - (3)].lex).string).size()));
+ } else {
+ if (fields.num == 1) {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.offsets[0]);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yyvsp[(3) - (3)].lex).line);
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line);
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision()));
+ } else {
+ TString vectorString = *(yyvsp[(3) - (3)].lex).string;
+ TIntermTyped* index = context->intermediate.addSwizzle(fields, (yyvsp[(3) - (3)].lex).line);
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpVectorSwizzle, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line);
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(), EvqTemporary, (int) vectorString.size()));
+ }
+ }
+ } else if ((yyvsp[(1) - (3)].interm.intermTypedNode)->isMatrix()) {
+ TMatrixFields fields;
+ if (! context->parseMatrixFields(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize(), fields, (yyvsp[(3) - (3)].lex).line)) {
+ fields.wholeRow = false;
+ fields.wholeCol = false;
+ fields.row = 0;
+ fields.col = 0;
+ context->recover();
+ }
+
+ if (fields.wholeRow || fields.wholeCol) {
+ context->error((yyvsp[(2) - (3)].lex).line, " non-scalar fields not implemented yet", ".", "");
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(0);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yyvsp[(3) - (3)].lex).line);
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line);
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision(),EvqTemporary, (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize()));
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(fields.col * (yyvsp[(1) - (3)].interm.intermTypedNode)->getNominalSize() + fields.row);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, TType(EbtInt, EbpUndefined, EvqConst), (yyvsp[(3) - (3)].lex).line);
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirect, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line);
+ (yyval.interm.intermTypedNode)->setType(TType((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType(), (yyvsp[(1) - (3)].interm.intermTypedNode)->getPrecision()));
+ }
+ } else if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getBasicType() == EbtStruct) {
+ bool fieldFound = false;
+ const TTypeList* fields = (yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getStruct();
+ if (fields == 0) {
+ context->error((yyvsp[(2) - (3)].lex).line, "structure has no fields", "Internal Error", "");
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ } else {
+ unsigned int i;
+ for (i = 0; i < fields->size(); ++i) {
+ if ((*fields)[i].type->getFieldName() == *(yyvsp[(3) - (3)].lex).string) {
+ fieldFound = true;
+ break;
+ }
+ }
+ if (fieldFound) {
+ if ((yyvsp[(1) - (3)].interm.intermTypedNode)->getType().getQualifier() == EvqConst) {
+ (yyval.interm.intermTypedNode) = context->addConstStruct(*(yyvsp[(3) - (3)].lex).string, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ else {
+ (yyval.interm.intermTypedNode)->setType(*(*fields)[i].type);
+ // change the qualifier of the return type, not of the structure field
+ // as the structure definition is shared between various structures.
+ (yyval.interm.intermTypedNode)->getTypePointer()->setQualifier(EvqConst);
+ }
+ } else {
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setIConst(i);
+ TIntermTyped* index = context->intermediate.addConstantUnion(unionArray, *(*fields)[i].type, (yyvsp[(3) - (3)].lex).line);
+ (yyval.interm.intermTypedNode) = context->intermediate.addIndex(EOpIndexDirectStruct, (yyvsp[(1) - (3)].interm.intermTypedNode), index, (yyvsp[(2) - (3)].lex).line);
+ (yyval.interm.intermTypedNode)->setType(*(*fields)[i].type);
+ }
+ } else {
+ context->error((yyvsp[(2) - (3)].lex).line, " no such field in structure", (yyvsp[(3) - (3)].lex).string->c_str(), "");
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ }
+ } else {
+ context->error((yyvsp[(2) - (3)].lex).line, " field selection requires structure, vector, or matrix on left hand side", (yyvsp[(3) - (3)].lex).string->c_str(), "");
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ // don't delete $3.string, it's from the pool
+ ;}
+ break;
+
+ case 12:
+
+ {
+ if (context->lValueErrorCheck((yyvsp[(2) - (2)].lex).line, "++", (yyvsp[(1) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostIncrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yyvsp[(2) - (2)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yyvsp[(2) - (2)].lex).line, "++", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 13:
+
+ {
+ if (context->lValueErrorCheck((yyvsp[(2) - (2)].lex).line, "--", (yyvsp[(1) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPostDecrement, (yyvsp[(1) - (2)].interm.intermTypedNode), (yyvsp[(2) - (2)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yyvsp[(2) - (2)].lex).line, "--", (yyvsp[(1) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 14:
+
+ {
+ if (context->integerErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode), "[]"))
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 15:
+
+ {
+ TFunction* fnCall = (yyvsp[(1) - (1)].interm).function;
+ TOperator op = fnCall->getBuiltInOp();
+
+ if (op != EOpNull)
+ {
+ //
+ // Then this should be a constructor.
+ // Don't go through the symbol table for constructors.
+ // Their parameters will be verified algorithmically.
+ //
+ TType type(EbtVoid, EbpUndefined); // use this to get the type back
+ if (context->constructorErrorCheck((yyvsp[(1) - (1)].interm).line, (yyvsp[(1) - (1)].interm).intermNode, *fnCall, op, &type)) {
+ (yyval.interm.intermTypedNode) = 0;
+ } else {
+ //
+ // It's a constructor, of type 'type'.
+ //
+ (yyval.interm.intermTypedNode) = context->addConstructor((yyvsp[(1) - (1)].interm).intermNode, &type, op, fnCall, (yyvsp[(1) - (1)].interm).line);
+ }
+
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator(0, op, (yyvsp[(1) - (1)].interm).line);
+ }
+ (yyval.interm.intermTypedNode)->setType(type);
+ } else {
+ //
+ // Not a constructor. Find it in the symbol table.
+ //
+ const TFunction* fnCandidate;
+ bool builtIn;
+ fnCandidate = context->findFunction((yyvsp[(1) - (1)].interm).line, fnCall, &builtIn);
+ if (fnCandidate) {
+ //
+ // A declared function.
+ //
+ if (builtIn && !fnCandidate->getExtension().empty() &&
+ context->extensionErrorCheck((yyvsp[(1) - (1)].interm).line, fnCandidate->getExtension())) {
+ context->recover();
+ }
+ op = fnCandidate->getBuiltInOp();
+ if (builtIn && op != EOpNull) {
+ //
+ // A function call mapped to a built-in operation.
+ //
+ if (fnCandidate->getParamCount() == 1) {
+ //
+ // Treat it like a built-in unary operator.
+ //
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(op, (yyvsp[(1) - (1)].interm).intermNode, 0, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), " wrong operand type", "Internal Error",
+ "built in unary operator function. Type: %s",
+ static_cast<TIntermTyped*>((yyvsp[(1) - (1)].interm).intermNode)->getCompleteString().c_str());
+ YYERROR;
+ }
+ } else {
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, op, (yyvsp[(1) - (1)].interm).line);
+ }
+ } else {
+ // This is a real function call
+
+ (yyval.interm.intermTypedNode) = context->intermediate.setAggregateOperator((yyvsp[(1) - (1)].interm).intermAggregate, EOpFunctionCall, (yyvsp[(1) - (1)].interm).line);
+ (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType());
+
+ // this is how we know whether the given function is a builtIn function or a user defined function
+ // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also
+ // if builtIn == true, it's definitely a builtIn function with EOpNull
+ if (!builtIn)
+ (yyval.interm.intermTypedNode)->getAsAggregate()->setUserDefined();
+ (yyval.interm.intermTypedNode)->getAsAggregate()->setName(fnCandidate->getMangledName());
+
+ TQualifier qual;
+ for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
+ qual = fnCandidate->getParam(i).type->getQualifier();
+ if (qual == EvqOut || qual == EvqInOut) {
+ if (context->lValueErrorCheck((yyval.interm.intermTypedNode)->getLine(), "assign", (yyval.interm.intermTypedNode)->getAsAggregate()->getSequence()[i]->getAsTyped())) {
+ context->error((yyvsp[(1) - (1)].interm).intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", "");
+ context->recover();
+ }
+ }
+ }
+ }
+ (yyval.interm.intermTypedNode)->setType(fnCandidate->getReturnType());
+ } else {
+ // error message was put out by PaFindFunction()
+ // Put on a dummy node for error recovery
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setFConst(0.0f);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtFloat, EbpUndefined, EvqConst), (yyvsp[(1) - (1)].interm).line);
+ context->recover();
+ }
+ }
+ delete fnCall;
+ ;}
+ break;
+
+ case 16:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (1)].interm);
+ ;}
+ break;
+
+ case 17:
+
+ {
+ context->error((yyvsp[(3) - (3)].interm).line, "methods are not supported", "", "");
+ context->recover();
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ ;}
+ break;
+
+ case 18:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (2)].interm);
+ (yyval.interm).line = (yyvsp[(2) - (2)].lex).line;
+ ;}
+ break;
+
+ case 19:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (2)].interm);
+ (yyval.interm).line = (yyvsp[(2) - (2)].lex).line;
+ ;}
+ break;
+
+ case 20:
+
+ {
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+ (yyval.interm).intermNode = 0;
+ ;}
+ break;
+
+ case 21:
+
+ {
+ (yyval.interm).function = (yyvsp[(1) - (1)].interm.function);
+ (yyval.interm).intermNode = 0;
+ ;}
+ break;
+
+ case 22:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(2) - (2)].interm.intermTypedNode)->getType()) };
+ (yyvsp[(1) - (2)].interm.function)->addParameter(param);
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+ (yyval.interm).intermNode = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 23:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(3) - (3)].interm.intermTypedNode)->getType()) };
+ (yyvsp[(1) - (3)].interm).function->addParameter(param);
+ (yyval.interm).function = (yyvsp[(1) - (3)].interm).function;
+ (yyval.interm).intermNode = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line);
+ ;}
+ break;
+
+ case 24:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function);
+ ;}
+ break;
+
+ case 25:
+
+ {
+ //
+ // Constructor
+ //
+ TOperator op = EOpNull;
+ if ((yyvsp[(1) - (1)].interm.type).userDef) {
+ op = EOpConstructStruct;
+ } else {
+ switch ((yyvsp[(1) - (1)].interm.type).type) {
+ case EbtFloat:
+ if ((yyvsp[(1) - (1)].interm.type).matrix) {
+ switch((yyvsp[(1) - (1)].interm.type).size) {
+ case 2: op = EOpConstructMat2; break;
+ case 3: op = EOpConstructMat3; break;
+ case 4: op = EOpConstructMat4; break;
+ }
+ } else {
+ switch((yyvsp[(1) - (1)].interm.type).size) {
+ case 1: op = EOpConstructFloat; break;
+ case 2: op = EOpConstructVec2; break;
+ case 3: op = EOpConstructVec3; break;
+ case 4: op = EOpConstructVec4; break;
+ }
+ }
+ break;
+ case EbtInt:
+ switch((yyvsp[(1) - (1)].interm.type).size) {
+ case 1: op = EOpConstructInt; break;
+ case 2: FRAG_VERT_ONLY("ivec2", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructIVec2; break;
+ case 3: FRAG_VERT_ONLY("ivec3", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructIVec3; break;
+ case 4: FRAG_VERT_ONLY("ivec4", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructIVec4; break;
+ }
+ break;
+ case EbtBool:
+ switch((yyvsp[(1) - (1)].interm.type).size) {
+ case 1: op = EOpConstructBool; break;
+ case 2: FRAG_VERT_ONLY("bvec2", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructBVec2; break;
+ case 3: FRAG_VERT_ONLY("bvec3", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructBVec3; break;
+ case 4: FRAG_VERT_ONLY("bvec4", (yyvsp[(1) - (1)].interm.type).line); op = EOpConstructBVec4; break;
+ }
+ break;
+ default: break;
+ }
+ if (op == EOpNull) {
+ context->error((yyvsp[(1) - (1)].interm.type).line, "cannot construct this type", getBasicString((yyvsp[(1) - (1)].interm.type).type), "");
+ context->recover();
+ (yyvsp[(1) - (1)].interm.type).type = EbtFloat;
+ op = EOpConstructFloat;
+ }
+ }
+ TString tempString;
+ TType type((yyvsp[(1) - (1)].interm.type));
+ TFunction *function = new TFunction(&tempString, type, op);
+ (yyval.interm.function) = function;
+ ;}
+ break;
+
+ case 26:
+
+ {
+ if (context->reservedErrorCheck((yyvsp[(1) - (1)].lex).line, *(yyvsp[(1) - (1)].lex).string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction((yyvsp[(1) - (1)].lex).string, type);
+ (yyval.interm.function) = function;
+ ;}
+ break;
+
+ case 27:
+
+ {
+ if (context->reservedErrorCheck((yyvsp[(1) - (1)].lex).line, *(yyvsp[(1) - (1)].lex).string))
+ context->recover();
+ TType type(EbtVoid, EbpUndefined);
+ TFunction *function = new TFunction((yyvsp[(1) - (1)].lex).string, type);
+ (yyval.interm.function) = function;
+ ;}
+ break;
+
+ case 28:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 29:
+
+ {
+ if (context->lValueErrorCheck((yyvsp[(1) - (2)].lex).line, "++", (yyvsp[(2) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreIncrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yyvsp[(1) - (2)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yyvsp[(1) - (2)].lex).line, "++", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 30:
+
+ {
+ if (context->lValueErrorCheck((yyvsp[(1) - (2)].lex).line, "--", (yyvsp[(2) - (2)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath(EOpPreDecrement, (yyvsp[(2) - (2)].interm.intermTypedNode), (yyvsp[(1) - (2)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->unaryOpError((yyvsp[(1) - (2)].lex).line, "--", (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 31:
+
+ {
+ if ((yyvsp[(1) - (2)].interm).op != EOpNull) {
+ (yyval.interm.intermTypedNode) = context->intermediate.addUnaryMath((yyvsp[(1) - (2)].interm).op, (yyvsp[(2) - (2)].interm.intermTypedNode), (yyvsp[(1) - (2)].interm).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ const char* errorOp = "";
+ switch((yyvsp[(1) - (2)].interm).op) {
+ case EOpNegative: errorOp = "-"; break;
+ case EOpLogicalNot: errorOp = "!"; break;
+ default: break;
+ }
+ context->unaryOpError((yyvsp[(1) - (2)].interm).line, errorOp, (yyvsp[(2) - (2)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ }
+ } else
+ (yyval.interm.intermTypedNode) = (yyvsp[(2) - (2)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 32:
+
+ { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpNull; ;}
+ break;
+
+ case 33:
+
+ { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpNegative; ;}
+ break;
+
+ case 34:
+
+ { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpLogicalNot; ;}
+ break;
+
+ case 35:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 36:
+
+ {
+ FRAG_VERT_ONLY("*", (yyvsp[(2) - (3)].lex).line);
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpMul, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "*", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 37:
+
+ {
+ FRAG_VERT_ONLY("/", (yyvsp[(2) - (3)].lex).line);
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpDiv, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "/", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 38:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 39:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpAdd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "+", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 40:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpSub, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "-", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 41:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 42:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 43:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "<", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 44:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThan, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, ">", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 45:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLessThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "<=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 46:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpGreaterThanEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, ">=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 47:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 48:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "==", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 49:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpNotEqual, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "!=", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 50:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 51:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 52:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 53:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 54:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalAnd, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "&&", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 55:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 56:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalXor, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "^^", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 57:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 58:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addBinaryMath(EOpLogicalOr, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line, context->symbolTable);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, "||", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ ConstantUnion *unionArray = new ConstantUnion[1];
+ unionArray->setBConst(false);
+ (yyval.interm.intermTypedNode) = context->intermediate.addConstantUnion(unionArray, TType(EbtBool, EbpUndefined, EvqConst), (yyvsp[(2) - (3)].lex).line);
+ }
+ ;}
+ break;
+
+ case 59:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 60:
+
+ {
+ if (context->boolErrorCheck((yyvsp[(2) - (5)].lex).line, (yyvsp[(1) - (5)].interm.intermTypedNode)))
+ context->recover();
+
+ (yyval.interm.intermTypedNode) = context->intermediate.addSelection((yyvsp[(1) - (5)].interm.intermTypedNode), (yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.intermTypedNode), (yyvsp[(2) - (5)].lex).line);
+ if ((yyvsp[(3) - (5)].interm.intermTypedNode)->getType() != (yyvsp[(5) - (5)].interm.intermTypedNode)->getType())
+ (yyval.interm.intermTypedNode) = 0;
+
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (5)].lex).line, ":", (yyvsp[(3) - (5)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(5) - (5)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(5) - (5)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 61:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 62:
+
+ {
+ if (context->lValueErrorCheck((yyvsp[(2) - (3)].interm).line, "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = context->intermediate.addAssign((yyvsp[(2) - (3)].interm).op, (yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].interm).line);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->assignError((yyvsp[(2) - (3)].interm).line, "assign", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 63:
+
+ { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpAssign; ;}
+ break;
+
+ case 64:
+
+ { FRAG_VERT_ONLY("*=", (yyvsp[(1) - (1)].lex).line); (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpMulAssign; ;}
+ break;
+
+ case 65:
+
+ { FRAG_VERT_ONLY("/=", (yyvsp[(1) - (1)].lex).line); (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpDivAssign; ;}
+ break;
+
+ case 66:
+
+ { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpAddAssign; ;}
+ break;
+
+ case 67:
+
+ { (yyval.interm).line = (yyvsp[(1) - (1)].lex).line; (yyval.interm).op = EOpSubAssign; ;}
+ break;
+
+ case 68:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 69:
+
+ {
+ (yyval.interm.intermTypedNode) = context->intermediate.addComma((yyvsp[(1) - (3)].interm.intermTypedNode), (yyvsp[(3) - (3)].interm.intermTypedNode), (yyvsp[(2) - (3)].lex).line);
+ if ((yyval.interm.intermTypedNode) == 0) {
+ context->binaryOpError((yyvsp[(2) - (3)].lex).line, ",", (yyvsp[(1) - (3)].interm.intermTypedNode)->getCompleteString(), (yyvsp[(3) - (3)].interm.intermTypedNode)->getCompleteString());
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(3) - (3)].interm.intermTypedNode);
+ }
+ ;}
+ break;
+
+ case 70:
+
+ {
+ if (context->constErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 71:
+
+ {
+ TFunction &function = *((yyvsp[(1) - (2)].interm).function);
+
+ TIntermAggregate *prototype = new TIntermAggregate;
+ prototype->setType(function.getReturnType());
+ prototype->setName(function.getName());
+
+ for (int i = 0; i < function.getParamCount(); i++)
+ {
+ const TParameter &param = function.getParam(i);
+ if (param.name != 0)
+ {
+ TVariable *variable = new TVariable(param.name, *param.type);
+
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), (yyvsp[(1) - (2)].interm).line), (yyvsp[(1) - (2)].interm).line);
+ }
+ else
+ {
+ prototype = context->intermediate.growAggregate(prototype, context->intermediate.addSymbol(0, "", *param.type, (yyvsp[(1) - (2)].interm).line), (yyvsp[(1) - (2)].interm).line);
+ }
+ }
+
+ prototype->setOp(EOpPrototype);
+ (yyval.interm.intermNode) = prototype;
+ ;}
+ break;
+
+ case 72:
+
+ {
+ if ((yyvsp[(1) - (2)].interm).intermAggregate)
+ (yyvsp[(1) - (2)].interm).intermAggregate->setOp(EOpDeclaration);
+ (yyval.interm.intermNode) = (yyvsp[(1) - (2)].interm).intermAggregate;
+ ;}
+ break;
+
+ case 73:
+
+ {
+ context->symbolTable.setDefaultPrecision( (yyvsp[(3) - (4)].interm.type).type, (yyvsp[(2) - (4)].interm.precision) );
+ (yyval.interm.intermNode) = 0;
+ ;}
+ break;
+
+ case 74:
+
+ {
+ //
+ // Multiple declarations of the same function are allowed.
+ //
+ // If this is a definition, the definition production code will check for redefinitions
+ // (we don't know at this point if it's a definition or not).
+ //
+ // Redeclarations are allowed. But, return types and parameter qualifiers must match.
+ //
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find((yyvsp[(1) - (2)].interm.function)->getMangledName()));
+ if (prevDec) {
+ if (prevDec->getReturnType() != (yyvsp[(1) - (2)].interm.function)->getReturnType()) {
+ context->error((yyvsp[(2) - (2)].lex).line, "overloaded functions must have the same return type", (yyvsp[(1) - (2)].interm.function)->getReturnType().getBasicString(), "");
+ context->recover();
+ }
+ for (int i = 0; i < prevDec->getParamCount(); ++i) {
+ if (prevDec->getParam(i).type->getQualifier() != (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifier()) {
+ context->error((yyvsp[(2) - (2)].lex).line, "overloaded functions must have the same parameter qualifiers", (yyvsp[(1) - (2)].interm.function)->getParam(i).type->getQualifierString(), "");
+ context->recover();
+ }
+ }
+ }
+
+ //
+ // If this is a redeclaration, it could also be a definition,
+ // in which case, we want to use the variable names from this one, and not the one that's
+ // being redeclared. So, pass back up this declaration, not the one in the symbol table.
+ //
+ (yyval.interm).function = (yyvsp[(1) - (2)].interm.function);
+ (yyval.interm).line = (yyvsp[(2) - (2)].lex).line;
+
+ context->symbolTable.insert(*(yyval.interm).function);
+ ;}
+ break;
+
+ case 75:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function);
+ ;}
+ break;
+
+ case 76:
+
+ {
+ (yyval.interm.function) = (yyvsp[(1) - (1)].interm.function);
+ ;}
+ break;
+
+ case 77:
+
+ {
+ // Add the parameter
+ (yyval.interm.function) = (yyvsp[(1) - (2)].interm.function);
+ if ((yyvsp[(2) - (2)].interm).param.type->getBasicType() != EbtVoid)
+ (yyvsp[(1) - (2)].interm.function)->addParameter((yyvsp[(2) - (2)].interm).param);
+ else
+ delete (yyvsp[(2) - (2)].interm).param.type;
+ ;}
+ break;
+
+ case 78:
+
+ {
+ //
+ // Only first parameter of one-parameter functions can be void
+ // The check for named parameters not being void is done in parameter_declarator
+ //
+ if ((yyvsp[(3) - (3)].interm).param.type->getBasicType() == EbtVoid) {
+ //
+ // This parameter > first is void
+ //
+ context->error((yyvsp[(2) - (3)].lex).line, "cannot be an argument type except for '(void)'", "void", "");
+ context->recover();
+ delete (yyvsp[(3) - (3)].interm).param.type;
+ } else {
+ // Add the parameter
+ (yyval.interm.function) = (yyvsp[(1) - (3)].interm.function);
+ (yyvsp[(1) - (3)].interm.function)->addParameter((yyvsp[(3) - (3)].interm).param);
+ }
+ ;}
+ break;
+
+ case 79:
+
+ {
+ if ((yyvsp[(1) - (3)].interm.type).qualifier != EvqGlobal && (yyvsp[(1) - (3)].interm.type).qualifier != EvqTemporary) {
+ context->error((yyvsp[(2) - (3)].lex).line, "no qualifiers allowed for function return", getQualifierString((yyvsp[(1) - (3)].interm.type).qualifier), "");
+ context->recover();
+ }
+ // make sure a sampler is not involved as well...
+ if (context->structQualifierErrorCheck((yyvsp[(2) - (3)].lex).line, (yyvsp[(1) - (3)].interm.type)))
+ context->recover();
+
+ // Add the function as a prototype after parsing it (we do not support recursion)
+ TFunction *function;
+ TType type((yyvsp[(1) - (3)].interm.type));
+ function = new TFunction((yyvsp[(2) - (3)].lex).string, type);
+ (yyval.interm.function) = function;
+ ;}
+ break;
+
+ case 80:
+
+ {
+ if ((yyvsp[(1) - (2)].interm.type).type == EbtVoid) {
+ context->error((yyvsp[(2) - (2)].lex).line, "illegal use of type 'void'", (yyvsp[(2) - (2)].lex).string->c_str(), "");
+ context->recover();
+ }
+ if (context->reservedErrorCheck((yyvsp[(2) - (2)].lex).line, *(yyvsp[(2) - (2)].lex).string))
+ context->recover();
+ TParameter param = {(yyvsp[(2) - (2)].lex).string, new TType((yyvsp[(1) - (2)].interm.type))};
+ (yyval.interm).line = (yyvsp[(2) - (2)].lex).line;
+ (yyval.interm).param = param;
+ ;}
+ break;
+
+ case 81:
+
+ {
+ // Check that we can make an array out of this type
+ if (context->arrayTypeErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm.type)))
+ context->recover();
+
+ if (context->reservedErrorCheck((yyvsp[(2) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string))
+ context->recover();
+
+ int size;
+ if (context->arraySizeErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(4) - (5)].interm.intermTypedNode), size))
+ context->recover();
+ (yyvsp[(1) - (5)].interm.type).setArray(true, size);
+
+ TType* type = new TType((yyvsp[(1) - (5)].interm.type));
+ TParameter param = { (yyvsp[(2) - (5)].lex).string, type };
+ (yyval.interm).line = (yyvsp[(2) - (5)].lex).line;
+ (yyval.interm).param = param;
+ ;}
+ break;
+
+ case 82:
+
+ {
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ if (context->paramErrorCheck((yyvsp[(3) - (3)].interm).line, (yyvsp[(1) - (3)].interm.type).qualifier, (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ ;}
+ break;
+
+ case 83:
+
+ {
+ (yyval.interm) = (yyvsp[(2) - (2)].interm);
+ if (context->parameterSamplerErrorCheck((yyvsp[(2) - (2)].interm).line, (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type))
+ context->recover();
+ if (context->paramErrorCheck((yyvsp[(2) - (2)].interm).line, EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ ;}
+ break;
+
+ case 84:
+
+ {
+ (yyval.interm) = (yyvsp[(3) - (3)].interm);
+ if (context->paramErrorCheck((yyvsp[(3) - (3)].interm).line, (yyvsp[(1) - (3)].interm.type).qualifier, (yyvsp[(2) - (3)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ ;}
+ break;
+
+ case 85:
+
+ {
+ (yyval.interm) = (yyvsp[(2) - (2)].interm);
+ if (context->parameterSamplerErrorCheck((yyvsp[(2) - (2)].interm).line, (yyvsp[(1) - (2)].interm.qualifier), *(yyvsp[(2) - (2)].interm).param.type))
+ context->recover();
+ if (context->paramErrorCheck((yyvsp[(2) - (2)].interm).line, EvqTemporary, (yyvsp[(1) - (2)].interm.qualifier), (yyval.interm).param.type))
+ context->recover();
+ ;}
+ break;
+
+ case 86:
+
+ {
+ (yyval.interm.qualifier) = EvqIn;
+ ;}
+ break;
+
+ case 87:
+
+ {
+ (yyval.interm.qualifier) = EvqIn;
+ ;}
+ break;
+
+ case 88:
+
+ {
+ (yyval.interm.qualifier) = EvqOut;
+ ;}
+ break;
+
+ case 89:
+
+ {
+ (yyval.interm.qualifier) = EvqInOut;
+ ;}
+ break;
+
+ case 90:
+
+ {
+ TParameter param = { 0, new TType((yyvsp[(1) - (1)].interm.type)) };
+ (yyval.interm).param = param;
+ ;}
+ break;
+
+ case 91:
+
+ {
+ (yyval.interm) = (yyvsp[(1) - (1)].interm);
+ ;}
+ break;
+
+ case 92:
+
+ {
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(3) - (3)].lex).string, TType((yyvsp[(1) - (3)].interm).type), (yyvsp[(3) - (3)].lex).line);
+ (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermNode, symbol, (yyvsp[(3) - (3)].lex).line);
+
+ if (context->structQualifierErrorCheck((yyvsp[(3) - (3)].lex).line, (yyval.interm).type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yyvsp[(3) - (3)].lex).line, *(yyvsp[(3) - (3)].lex).string, (yyval.interm).type))
+ context->recover();
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck((yyvsp[(3) - (3)].lex).line, *(yyvsp[(3) - (3)].lex).string, (yyval.interm).type, variable))
+ context->recover();
+ if (symbol && variable)
+ symbol->setId(variable->getUniqueId());
+ ;}
+ break;
+
+ case 93:
+
+ {
+ if (context->structQualifierErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm).type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yyvsp[(3) - (5)].lex).line, *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type))
+ context->recover();
+
+ (yyval.interm) = (yyvsp[(1) - (5)].interm);
+
+ if (context->arrayTypeErrorCheck((yyvsp[(4) - (5)].lex).line, (yyvsp[(1) - (5)].interm).type) || context->arrayQualifierErrorCheck((yyvsp[(4) - (5)].lex).line, (yyvsp[(1) - (5)].interm).type))
+ context->recover();
+ else {
+ (yyvsp[(1) - (5)].interm).type.setArray(true);
+ TVariable* variable;
+ if (context->arrayErrorCheck((yyvsp[(4) - (5)].lex).line, *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, variable))
+ context->recover();
+ }
+ ;}
+ break;
+
+ case 94:
+
+ {
+ if (context->structQualifierErrorCheck((yyvsp[(3) - (6)].lex).line, (yyvsp[(1) - (6)].interm).type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yyvsp[(3) - (6)].lex).line, *(yyvsp[(3) - (6)].lex).string, (yyvsp[(1) - (6)].interm).type))
+ context->recover();
+
+ (yyval.interm) = (yyvsp[(1) - (6)].interm);
+
+ if (context->arrayTypeErrorCheck((yyvsp[(4) - (6)].lex).line, (yyvsp[(1) - (6)].interm).type) || context->arrayQualifierErrorCheck((yyvsp[(4) - (6)].lex).line, (yyvsp[(1) - (6)].interm).type))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck((yyvsp[(4) - (6)].lex).line, (yyvsp[(5) - (6)].interm.intermTypedNode), size))
+ context->recover();
+ (yyvsp[(1) - (6)].interm).type.setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck((yyvsp[(4) - (6)].lex).line, *(yyvsp[(3) - (6)].lex).string, (yyvsp[(1) - (6)].interm).type, variable))
+ context->recover();
+ TType type = TType((yyvsp[(1) - (6)].interm).type);
+ type.setArraySize(size);
+ (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (6)].interm).intermNode, context->intermediate.addSymbol(variable ? variable->getUniqueId() : 0, *(yyvsp[(3) - (6)].lex).string, type, (yyvsp[(3) - (6)].lex).line), (yyvsp[(3) - (6)].lex).line);
+ }
+ ;}
+ break;
+
+ case 95:
+
+ {
+ if (context->structQualifierErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm).type))
+ context->recover();
+
+ (yyval.interm) = (yyvsp[(1) - (5)].interm);
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer((yyvsp[(3) - (5)].lex).line, *(yyvsp[(3) - (5)].lex).string, (yyvsp[(1) - (5)].interm).type, (yyvsp[(5) - (5)].interm.intermTypedNode), intermNode)) {
+ //
+ // build the intermediate representation
+ //
+ if (intermNode)
+ (yyval.interm).intermAggregate = context->intermediate.growAggregate((yyvsp[(1) - (5)].interm).intermNode, intermNode, (yyvsp[(4) - (5)].lex).line);
+ else
+ (yyval.interm).intermAggregate = (yyvsp[(1) - (5)].interm).intermAggregate;
+ } else {
+ context->recover();
+ (yyval.interm).intermAggregate = 0;
+ }
+ ;}
+ break;
+
+ case 96:
+
+ {
+ (yyval.interm).type = (yyvsp[(1) - (1)].interm.type);
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(context->intermediate.addSymbol(0, "", TType((yyvsp[(1) - (1)].interm.type)), (yyvsp[(1) - (1)].interm.type).line), (yyvsp[(1) - (1)].interm.type).line);
+ ;}
+ break;
+
+ case 97:
+
+ {
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (2)].lex).string, TType((yyvsp[(1) - (2)].interm.type)), (yyvsp[(2) - (2)].lex).line);
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yyvsp[(2) - (2)].lex).line);
+
+ if (context->structQualifierErrorCheck((yyvsp[(2) - (2)].lex).line, (yyval.interm).type))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yyvsp[(2) - (2)].lex).line, *(yyvsp[(2) - (2)].lex).string, (yyval.interm).type))
+ context->recover();
+
+ (yyval.interm).type = (yyvsp[(1) - (2)].interm.type);
+
+ TVariable* variable = 0;
+ if (context->nonInitErrorCheck((yyvsp[(2) - (2)].lex).line, *(yyvsp[(2) - (2)].lex).string, (yyval.interm).type, variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ ;}
+ break;
+
+ case 98:
+
+ {
+ context->error((yyvsp[(2) - (4)].lex).line, "unsized array declarations not supported", (yyvsp[(2) - (4)].lex).string->c_str(), "");
+ context->recover();
+
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (4)].lex).string, TType((yyvsp[(1) - (4)].interm.type)), (yyvsp[(2) - (4)].lex).line);
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yyvsp[(2) - (4)].lex).line);
+ (yyval.interm).type = (yyvsp[(1) - (4)].interm.type);
+ ;}
+ break;
+
+ case 99:
+
+ {
+ TType type = TType((yyvsp[(1) - (5)].interm.type));
+ int size;
+ if (context->arraySizeErrorCheck((yyvsp[(2) - (5)].lex).line, (yyvsp[(4) - (5)].interm.intermTypedNode), size))
+ context->recover();
+ type.setArraySize(size);
+ TIntermSymbol* symbol = context->intermediate.addSymbol(0, *(yyvsp[(2) - (5)].lex).string, type, (yyvsp[(2) - (5)].lex).line);
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(symbol, (yyvsp[(2) - (5)].lex).line);
+
+ if (context->structQualifierErrorCheck((yyvsp[(2) - (5)].lex).line, (yyvsp[(1) - (5)].interm.type)))
+ context->recover();
+
+ if (context->nonInitConstErrorCheck((yyvsp[(2) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string, (yyvsp[(1) - (5)].interm.type)))
+ context->recover();
+
+ (yyval.interm).type = (yyvsp[(1) - (5)].interm.type);
+
+ if (context->arrayTypeErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm.type)) || context->arrayQualifierErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(1) - (5)].interm.type)))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck((yyvsp[(3) - (5)].lex).line, (yyvsp[(4) - (5)].interm.intermTypedNode), size))
+ context->recover();
+
+ (yyvsp[(1) - (5)].interm.type).setArray(true, size);
+ TVariable* variable = 0;
+ if (context->arrayErrorCheck((yyvsp[(3) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string, (yyvsp[(1) - (5)].interm.type), variable))
+ context->recover();
+ if (variable && symbol)
+ symbol->setId(variable->getUniqueId());
+ }
+ ;}
+ break;
+
+ case 100:
+
+ {
+ if (context->structQualifierErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+
+ (yyval.interm).type = (yyvsp[(1) - (4)].interm.type);
+
+ TIntermNode* intermNode;
+ if (!context->executeInitializer((yyvsp[(2) - (4)].lex).line, *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), (yyvsp[(4) - (4)].interm.intermTypedNode), intermNode)) {
+ //
+ // Build intermediate representation
+ //
+ if(intermNode)
+ (yyval.interm).intermAggregate = context->intermediate.makeAggregate(intermNode, (yyvsp[(3) - (4)].lex).line);
+ else
+ (yyval.interm).intermAggregate = 0;
+ } else {
+ context->recover();
+ (yyval.interm).intermAggregate = 0;
+ }
+ ;}
+ break;
+
+ case 101:
+
+ {
+ VERTEX_ONLY("invariant declaration", (yyvsp[(1) - (2)].lex).line);
+ (yyval.interm).qualifier = EvqInvariantVaryingOut;
+ (yyval.interm).intermAggregate = 0;
+ ;}
+ break;
+
+ case 102:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+
+ if ((yyvsp[(1) - (1)].interm.type).array) {
+ context->error((yyvsp[(1) - (1)].interm.type).line, "not supported", "first-class array", "");
+ context->recover();
+ (yyvsp[(1) - (1)].interm.type).setArray(false);
+ }
+ ;}
+ break;
+
+ case 103:
+
+ {
+ if ((yyvsp[(2) - (2)].interm.type).array) {
+ context->error((yyvsp[(2) - (2)].interm.type).line, "not supported", "first-class array", "");
+ context->recover();
+ (yyvsp[(2) - (2)].interm.type).setArray(false);
+ }
+
+ if ((yyvsp[(1) - (2)].interm.type).qualifier == EvqAttribute &&
+ ((yyvsp[(2) - (2)].interm.type).type == EbtBool || (yyvsp[(2) - (2)].interm.type).type == EbtInt)) {
+ context->error((yyvsp[(2) - (2)].interm.type).line, "cannot be bool or int", getQualifierString((yyvsp[(1) - (2)].interm.type).qualifier), "");
+ context->recover();
+ }
+ if (((yyvsp[(1) - (2)].interm.type).qualifier == EvqVaryingIn || (yyvsp[(1) - (2)].interm.type).qualifier == EvqVaryingOut) &&
+ ((yyvsp[(2) - (2)].interm.type).type == EbtBool || (yyvsp[(2) - (2)].interm.type).type == EbtInt)) {
+ context->error((yyvsp[(2) - (2)].interm.type).line, "cannot be bool or int", getQualifierString((yyvsp[(1) - (2)].interm.type).qualifier), "");
+ context->recover();
+ }
+ (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type);
+ (yyval.interm.type).qualifier = (yyvsp[(1) - (2)].interm.type).qualifier;
+ ;}
+ break;
+
+ case 104:
+
+ {
+ (yyval.interm.type).setBasic(EbtVoid, EvqConst, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 105:
+
+ {
+ VERTEX_ONLY("attribute", (yyvsp[(1) - (1)].lex).line);
+ if (context->globalErrorCheck((yyvsp[(1) - (1)].lex).line, context->symbolTable.atGlobalLevel(), "attribute"))
+ context->recover();
+ (yyval.interm.type).setBasic(EbtVoid, EvqAttribute, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 106:
+
+ {
+ if (context->globalErrorCheck((yyvsp[(1) - (1)].lex).line, context->symbolTable.atGlobalLevel(), "varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ (yyval.interm.type).setBasic(EbtVoid, EvqVaryingOut, (yyvsp[(1) - (1)].lex).line);
+ else
+ (yyval.interm.type).setBasic(EbtVoid, EvqVaryingIn, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 107:
+
+ {
+ if (context->globalErrorCheck((yyvsp[(1) - (2)].lex).line, context->symbolTable.atGlobalLevel(), "invariant varying"))
+ context->recover();
+ if (context->shaderType == SH_VERTEX_SHADER)
+ (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingOut, (yyvsp[(1) - (2)].lex).line);
+ else
+ (yyval.interm.type).setBasic(EbtVoid, EvqInvariantVaryingIn, (yyvsp[(1) - (2)].lex).line);
+ ;}
+ break;
+
+ case 108:
+
+ {
+ if (context->globalErrorCheck((yyvsp[(1) - (1)].lex).line, context->symbolTable.atGlobalLevel(), "uniform"))
+ context->recover();
+ (yyval.interm.type).setBasic(EbtVoid, EvqUniform, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 109:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+
+ if ((yyval.interm.type).precision == EbpUndefined) {
+ (yyval.interm.type).precision = context->symbolTable.getDefaultPrecision((yyvsp[(1) - (1)].interm.type).type);
+ if (context->precisionErrorCheck((yyvsp[(1) - (1)].interm.type).line, (yyval.interm.type).precision, (yyvsp[(1) - (1)].interm.type).type)) {
+ context->recover();
+ }
+ }
+ ;}
+ break;
+
+ case 110:
+
+ {
+ (yyval.interm.type) = (yyvsp[(2) - (2)].interm.type);
+ (yyval.interm.type).precision = (yyvsp[(1) - (2)].interm.precision);
+ ;}
+ break;
+
+ case 111:
+
+ {
+ (yyval.interm.precision) = EbpHigh;
+ ;}
+ break;
+
+ case 112:
+
+ {
+ (yyval.interm.precision) = EbpMedium;
+ ;}
+ break;
+
+ case 113:
+
+ {
+ (yyval.interm.precision) = EbpLow;
+ ;}
+ break;
+
+ case 114:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+ ;}
+ break;
+
+ case 115:
+
+ {
+ (yyval.interm.type) = (yyvsp[(1) - (4)].interm.type);
+
+ if (context->arrayTypeErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+ else {
+ int size;
+ if (context->arraySizeErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(3) - (4)].interm.intermTypedNode), size))
+ context->recover();
+ (yyval.interm.type).setArray(true, size);
+ }
+ ;}
+ break;
+
+ case 116:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtVoid, qual, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 117:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 118:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 119:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 120:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(2);
+ ;}
+ break;
+
+ case 121:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(3);
+ ;}
+ break;
+
+ case 122:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(4);
+ ;}
+ break;
+
+ case 123:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(2);
+ ;}
+ break;
+
+ case 124:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(3);
+ ;}
+ break;
+
+ case 125:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtBool, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(4);
+ ;}
+ break;
+
+ case 126:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(2);
+ ;}
+ break;
+
+ case 127:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(3);
+ ;}
+ break;
+
+ case 128:
+
+ {
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtInt, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(4);
+ ;}
+ break;
+
+ case 129:
+
+ {
+ FRAG_VERT_ONLY("mat2", (yyvsp[(1) - (1)].lex).line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(2, true);
+ ;}
+ break;
+
+ case 130:
+
+ {
+ FRAG_VERT_ONLY("mat3", (yyvsp[(1) - (1)].lex).line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(3, true);
+ ;}
+ break;
+
+ case 131:
+
+ {
+ FRAG_VERT_ONLY("mat4", (yyvsp[(1) - (1)].lex).line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtFloat, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).setAggregate(4, true);
+ ;}
+ break;
+
+ case 132:
+
+ {
+ FRAG_VERT_ONLY("sampler2D", (yyvsp[(1) - (1)].lex).line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSampler2D, qual, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 133:
+
+ {
+ FRAG_VERT_ONLY("samplerCube", (yyvsp[(1) - (1)].lex).line);
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtSamplerCube, qual, (yyvsp[(1) - (1)].lex).line);
+ ;}
+ break;
+
+ case 134:
+
+ {
+ FRAG_VERT_ONLY("struct", (yyvsp[(1) - (1)].interm.type).line);
+ (yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
+ (yyval.interm.type).qualifier = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ ;}
+ break;
+
+ case 135:
+
+ {
+ //
+ // This is for user defined type names. The lexical phase looked up the
+ // type.
+ //
+ TType& structure = static_cast<TVariable*>((yyvsp[(1) - (1)].lex).symbol)->getType();
+ TQualifier qual = context->symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary;
+ (yyval.interm.type).setBasic(EbtStruct, qual, (yyvsp[(1) - (1)].lex).line);
+ (yyval.interm.type).userDef = &structure;
+ ;}
+ break;
+
+ case 136:
+
+ {
+ if (context->reservedErrorCheck((yyvsp[(2) - (5)].lex).line, *(yyvsp[(2) - (5)].lex).string))
+ context->recover();
+
+ TType* structure = new TType((yyvsp[(4) - (5)].interm.typeList), *(yyvsp[(2) - (5)].lex).string);
+ TVariable* userTypeDef = new TVariable((yyvsp[(2) - (5)].lex).string, *structure, true);
+ if (! context->symbolTable.insert(*userTypeDef)) {
+ context->error((yyvsp[(2) - (5)].lex).line, "redefinition", (yyvsp[(2) - (5)].lex).string->c_str(), "struct");
+ context->recover();
+ }
+ (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yyvsp[(1) - (5)].lex).line);
+ (yyval.interm.type).userDef = structure;
+ ;}
+ break;
+
+ case 137:
+
+ {
+ TType* structure = new TType((yyvsp[(3) - (4)].interm.typeList), TString(""));
+ (yyval.interm.type).setBasic(EbtStruct, EvqTemporary, (yyvsp[(1) - (4)].lex).line);
+ (yyval.interm.type).userDef = structure;
+ ;}
+ break;
+
+ case 138:
+
+ {
+ (yyval.interm.typeList) = (yyvsp[(1) - (1)].interm.typeList);
+ ;}
+ break;
+
+ case 139:
+
+ {
+ (yyval.interm.typeList) = (yyvsp[(1) - (2)].interm.typeList);
+ for (unsigned int i = 0; i < (yyvsp[(2) - (2)].interm.typeList)->size(); ++i) {
+ for (unsigned int j = 0; j < (yyval.interm.typeList)->size(); ++j) {
+ if ((*(yyval.interm.typeList))[j].type->getFieldName() == (*(yyvsp[(2) - (2)].interm.typeList))[i].type->getFieldName()) {
+ context->error((*(yyvsp[(2) - (2)].interm.typeList))[i].line, "duplicate field name in structure:", "struct", (*(yyvsp[(2) - (2)].interm.typeList))[i].type->getFieldName().c_str());
+ context->recover();
+ }
+ }
+ (yyval.interm.typeList)->push_back((*(yyvsp[(2) - (2)].interm.typeList))[i]);
+ }
+ ;}
+ break;
+
+ case 140:
+
+ {
+ (yyval.interm.typeList) = (yyvsp[(2) - (3)].interm.typeList);
+
+ if (context->voidErrorCheck((yyvsp[(1) - (3)].interm.type).line, (*(yyvsp[(2) - (3)].interm.typeList))[0].type->getFieldName(), (yyvsp[(1) - (3)].interm.type))) {
+ context->recover();
+ }
+ for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) {
+ //
+ // Careful not to replace already known aspects of type, like array-ness
+ //
+ TType* type = (*(yyval.interm.typeList))[i].type;
+ type->setBasicType((yyvsp[(1) - (3)].interm.type).type);
+ type->setNominalSize((yyvsp[(1) - (3)].interm.type).size);
+ type->setMatrix((yyvsp[(1) - (3)].interm.type).matrix);
+ type->setPrecision((yyvsp[(1) - (3)].interm.type).precision);
+
+ // don't allow arrays of arrays
+ if (type->isArray()) {
+ if (context->arrayTypeErrorCheck((yyvsp[(1) - (3)].interm.type).line, (yyvsp[(1) - (3)].interm.type)))
+ context->recover();
+ }
+ if ((yyvsp[(1) - (3)].interm.type).array)
+ type->setArraySize((yyvsp[(1) - (3)].interm.type).arraySize);
+ if ((yyvsp[(1) - (3)].interm.type).userDef) {
+ type->setStruct((yyvsp[(1) - (3)].interm.type).userDef->getStruct());
+ type->setTypeName((yyvsp[(1) - (3)].interm.type).userDef->getTypeName());
+ }
+ }
+ ;}
+ break;
+
+ case 141:
+
+ {
+ (yyval.interm.typeList) = NewPoolTTypeList();
+ (yyval.interm.typeList)->push_back((yyvsp[(1) - (1)].interm.typeLine));
+ ;}
+ break;
+
+ case 142:
+
+ {
+ (yyval.interm.typeList)->push_back((yyvsp[(3) - (3)].interm.typeLine));
+ ;}
+ break;
+
+ case 143:
+
+ {
+ if (context->reservedErrorCheck((yyvsp[(1) - (1)].lex).line, *(yyvsp[(1) - (1)].lex).string))
+ context->recover();
+
+ (yyval.interm.typeLine).type = new TType(EbtVoid, EbpUndefined);
+ (yyval.interm.typeLine).line = (yyvsp[(1) - (1)].lex).line;
+ (yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (1)].lex).string);
+ ;}
+ break;
+
+ case 144:
+
+ {
+ if (context->reservedErrorCheck((yyvsp[(1) - (4)].lex).line, *(yyvsp[(1) - (4)].lex).string))
+ context->recover();
+
+ (yyval.interm.typeLine).type = new TType(EbtVoid, EbpUndefined);
+ (yyval.interm.typeLine).line = (yyvsp[(1) - (4)].lex).line;
+ (yyval.interm.typeLine).type->setFieldName(*(yyvsp[(1) - (4)].lex).string);
+
+ int size;
+ if (context->arraySizeErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(3) - (4)].interm.intermTypedNode), size))
+ context->recover();
+ (yyval.interm.typeLine).type->setArraySize(size);
+ ;}
+ break;
+
+ case 145:
+
+ { (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode); ;}
+ break;
+
+ case 146:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 147:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermAggregate); ;}
+ break;
+
+ case 148:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 149:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 150:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 151:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 152:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 153:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 154:
+
+ { (yyval.interm.intermAggregate) = 0; ;}
+ break;
+
+ case 155:
+
+ { context->symbolTable.push(); ;}
+ break;
+
+ case 156:
+
+ { context->symbolTable.pop(); ;}
+ break;
+
+ case 157:
+
+ {
+ if ((yyvsp[(3) - (5)].interm.intermAggregate) != 0) {
+ (yyvsp[(3) - (5)].interm.intermAggregate)->setOp(EOpSequence);
+ (yyvsp[(3) - (5)].interm.intermAggregate)->setEndLine((yyvsp[(5) - (5)].lex).line);
+ }
+ (yyval.interm.intermAggregate) = (yyvsp[(3) - (5)].interm.intermAggregate);
+ ;}
+ break;
+
+ case 158:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 159:
+
+ { (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode); ;}
+ break;
+
+ case 160:
+
+ {
+ (yyval.interm.intermNode) = 0;
+ ;}
+ break;
+
+ case 161:
+
+ {
+ if ((yyvsp[(2) - (3)].interm.intermAggregate)) {
+ (yyvsp[(2) - (3)].interm.intermAggregate)->setOp(EOpSequence);
+ (yyvsp[(2) - (3)].interm.intermAggregate)->setEndLine((yyvsp[(3) - (3)].lex).line);
+ }
+ (yyval.interm.intermNode) = (yyvsp[(2) - (3)].interm.intermAggregate);
+ ;}
+ break;
+
+ case 162:
+
+ {
+ (yyval.interm.intermAggregate) = context->intermediate.makeAggregate((yyvsp[(1) - (1)].interm.intermNode), 0);
+ ;}
+ break;
+
+ case 163:
+
+ {
+ (yyval.interm.intermAggregate) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermAggregate), (yyvsp[(2) - (2)].interm.intermNode), 0);
+ ;}
+ break;
+
+ case 164:
+
+ { (yyval.interm.intermNode) = 0; ;}
+ break;
+
+ case 165:
+
+ { (yyval.interm.intermNode) = static_cast<TIntermNode*>((yyvsp[(1) - (2)].interm.intermTypedNode)); ;}
+ break;
+
+ case 166:
+
+ {
+ if (context->boolErrorCheck((yyvsp[(1) - (5)].lex).line, (yyvsp[(3) - (5)].interm.intermTypedNode)))
+ context->recover();
+ (yyval.interm.intermNode) = context->intermediate.addSelection((yyvsp[(3) - (5)].interm.intermTypedNode), (yyvsp[(5) - (5)].interm.nodePair), (yyvsp[(1) - (5)].lex).line);
+ ;}
+ break;
+
+ case 167:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermNode);
+ ;}
+ break;
+
+ case 168:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (1)].interm.intermNode);
+ (yyval.interm.nodePair).node2 = 0;
+ ;}
+ break;
+
+ case 169:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ if (context->boolErrorCheck((yyvsp[(1) - (1)].interm.intermTypedNode)->getLine(), (yyvsp[(1) - (1)].interm.intermTypedNode)))
+ context->recover();
+ ;}
+ break;
+
+ case 170:
+
+ {
+ TIntermNode* intermNode;
+ if (context->structQualifierErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+ if (context->boolErrorCheck((yyvsp[(2) - (4)].lex).line, (yyvsp[(1) - (4)].interm.type)))
+ context->recover();
+
+ if (!context->executeInitializer((yyvsp[(2) - (4)].lex).line, *(yyvsp[(2) - (4)].lex).string, (yyvsp[(1) - (4)].interm.type), (yyvsp[(4) - (4)].interm.intermTypedNode), intermNode))
+ (yyval.interm.intermTypedNode) = (yyvsp[(4) - (4)].interm.intermTypedNode);
+ else {
+ context->recover();
+ (yyval.interm.intermTypedNode) = 0;
+ }
+ ;}
+ break;
+
+ case 171:
+
+ { context->symbolTable.push(); ++context->loopNestingLevel; ;}
+ break;
+
+ case 172:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopWhile, 0, (yyvsp[(4) - (6)].interm.intermTypedNode), 0, (yyvsp[(6) - (6)].interm.intermNode), (yyvsp[(1) - (6)].lex).line);
+ --context->loopNestingLevel;
+ ;}
+ break;
+
+ case 173:
+
+ { ++context->loopNestingLevel; ;}
+ break;
+
+ case 174:
+
+ {
+ if (context->boolErrorCheck((yyvsp[(8) - (8)].lex).line, (yyvsp[(6) - (8)].interm.intermTypedNode)))
+ context->recover();
+
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopDoWhile, 0, (yyvsp[(6) - (8)].interm.intermTypedNode), 0, (yyvsp[(3) - (8)].interm.intermNode), (yyvsp[(4) - (8)].lex).line);
+ --context->loopNestingLevel;
+ ;}
+ break;
+
+ case 175:
+
+ { context->symbolTable.push(); ++context->loopNestingLevel; ;}
+ break;
+
+ case 176:
+
+ {
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.addLoop(ELoopFor, (yyvsp[(4) - (7)].interm.intermNode), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node1), reinterpret_cast<TIntermTyped*>((yyvsp[(5) - (7)].interm.nodePair).node2), (yyvsp[(7) - (7)].interm.intermNode), (yyvsp[(1) - (7)].lex).line);
+ --context->loopNestingLevel;
+ ;}
+ break;
+
+ case 177:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ ;}
+ break;
+
+ case 178:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ ;}
+ break;
+
+ case 179:
+
+ {
+ (yyval.interm.intermTypedNode) = (yyvsp[(1) - (1)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 180:
+
+ {
+ (yyval.interm.intermTypedNode) = 0;
+ ;}
+ break;
+
+ case 181:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (2)].interm.intermTypedNode);
+ (yyval.interm.nodePair).node2 = 0;
+ ;}
+ break;
+
+ case 182:
+
+ {
+ (yyval.interm.nodePair).node1 = (yyvsp[(1) - (3)].interm.intermTypedNode);
+ (yyval.interm.nodePair).node2 = (yyvsp[(3) - (3)].interm.intermTypedNode);
+ ;}
+ break;
+
+ case 183:
+
+ {
+ if (context->loopNestingLevel <= 0) {
+ context->error((yyvsp[(1) - (2)].lex).line, "continue statement only allowed in loops", "", "");
+ context->recover();
+ }
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpContinue, (yyvsp[(1) - (2)].lex).line);
+ ;}
+ break;
+
+ case 184:
+
+ {
+ if (context->loopNestingLevel <= 0) {
+ context->error((yyvsp[(1) - (2)].lex).line, "break statement only allowed in loops", "", "");
+ context->recover();
+ }
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpBreak, (yyvsp[(1) - (2)].lex).line);
+ ;}
+ break;
+
+ case 185:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(1) - (2)].lex).line);
+ if (context->currentFunctionType->getBasicType() != EbtVoid) {
+ context->error((yyvsp[(1) - (2)].lex).line, "non-void function must return a value", "return", "");
+ context->recover();
+ }
+ ;}
+ break;
+
+ case 186:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpReturn, (yyvsp[(2) - (3)].interm.intermTypedNode), (yyvsp[(1) - (3)].lex).line);
+ context->functionReturnsValue = true;
+ if (context->currentFunctionType->getBasicType() == EbtVoid) {
+ context->error((yyvsp[(1) - (3)].lex).line, "void function cannot return a value", "return", "");
+ context->recover();
+ } else if (*(context->currentFunctionType) != (yyvsp[(2) - (3)].interm.intermTypedNode)->getType()) {
+ context->error((yyvsp[(1) - (3)].lex).line, "function return is not matching type:", "return", "");
+ context->recover();
+ }
+ ;}
+ break;
+
+ case 187:
+
+ {
+ FRAG_ONLY("discard", (yyvsp[(1) - (2)].lex).line);
+ (yyval.interm.intermNode) = context->intermediate.addBranch(EOpKill, (yyvsp[(1) - (2)].lex).line);
+ ;}
+ break;
+
+ case 188:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ context->treeRoot = (yyval.interm.intermNode);
+ ;}
+ break;
+
+ case 189:
+
+ {
+ (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (2)].interm.intermNode), (yyvsp[(2) - (2)].interm.intermNode), 0);
+ context->treeRoot = (yyval.interm.intermNode);
+ ;}
+ break;
+
+ case 190:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ ;}
+ break;
+
+ case 191:
+
+ {
+ (yyval.interm.intermNode) = (yyvsp[(1) - (1)].interm.intermNode);
+ ;}
+ break;
+
+ case 192:
+
+ {
+ TFunction* function = (yyvsp[(1) - (1)].interm).function;
+ TFunction* prevDec = static_cast<TFunction*>(context->symbolTable.find(function->getMangledName()));
+ //
+ // Note: 'prevDec' could be 'function' if this is the first time we've seen function
+ // as it would have just been put in the symbol table. Otherwise, we're looking up
+ // an earlier occurance.
+ //
+ if (prevDec->isDefined()) {
+ //
+ // Then this function already has a body.
+ //
+ context->error((yyvsp[(1) - (1)].interm).line, "function already has a body", function->getName().c_str(), "");
+ context->recover();
+ }
+ prevDec->setDefined();
+
+ //
+ // Raise error message if main function takes any parameters or return anything other than void
+ //
+ if (function->getName() == "main") {
+ if (function->getParamCount() > 0) {
+ context->error((yyvsp[(1) - (1)].interm).line, "function cannot take any parameter(s)", function->getName().c_str(), "");
+ context->recover();
+ }
+ if (function->getReturnType().getBasicType() != EbtVoid) {
+ context->error((yyvsp[(1) - (1)].interm).line, "", function->getReturnType().getBasicString(), "main function cannot return a value");
+ context->recover();
+ }
+ }
+
+ //
+ // New symbol table scope for body of function plus its arguments
+ //
+ context->symbolTable.push();
+
+ //
+ // Remember the return type for later checking for RETURN statements.
+ //
+ context->currentFunctionType = &(prevDec->getReturnType());
+ context->functionReturnsValue = false;
+
+ //
+ // Insert parameters into the symbol table.
+ // If the parameter has no name, it's not an error, just don't insert it
+ // (could be used for unused args).
+ //
+ // Also, accumulate the list of parameters into the HIL, so lower level code
+ // knows where to find parameters.
+ //
+ TIntermAggregate* paramNodes = new TIntermAggregate;
+ for (int i = 0; i < function->getParamCount(); i++) {
+ const TParameter& param = function->getParam(i);
+ if (param.name != 0) {
+ TVariable *variable = new TVariable(param.name, *param.type);
+ //
+ // Insert the parameters with name in the symbol table.
+ //
+ if (! context->symbolTable.insert(*variable)) {
+ context->error((yyvsp[(1) - (1)].interm).line, "redefinition", variable->getName().c_str(), "");
+ context->recover();
+ delete variable;
+ }
+
+ //
+ // Add the parameter to the HIL
+ //
+ paramNodes = context->intermediate.growAggregate(
+ paramNodes,
+ context->intermediate.addSymbol(variable->getUniqueId(),
+ variable->getName(),
+ variable->getType(), (yyvsp[(1) - (1)].interm).line),
+ (yyvsp[(1) - (1)].interm).line);
+ } else {
+ paramNodes = context->intermediate.growAggregate(paramNodes, context->intermediate.addSymbol(0, "", *param.type, (yyvsp[(1) - (1)].interm).line), (yyvsp[(1) - (1)].interm).line);
+ }
+ }
+ context->intermediate.setAggregateOperator(paramNodes, EOpParameters, (yyvsp[(1) - (1)].interm).line);
+ (yyvsp[(1) - (1)].interm).intermAggregate = paramNodes;
+ context->loopNestingLevel = 0;
+ ;}
+ break;
+
+ case 193:
+
+ {
+ //?? Check that all paths return a value if return type != void ?
+ // May be best done as post process phase on intermediate code
+ if (context->currentFunctionType->getBasicType() != EbtVoid && ! context->functionReturnsValue) {
+ context->error((yyvsp[(1) - (3)].interm).line, "function does not return a value:", "", (yyvsp[(1) - (3)].interm).function->getName().c_str());
+ context->recover();
+ }
+ context->symbolTable.pop();
+ (yyval.interm.intermNode) = context->intermediate.growAggregate((yyvsp[(1) - (3)].interm).intermAggregate, (yyvsp[(3) - (3)].interm.intermNode), 0);
+ context->intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yyvsp[(1) - (3)].interm).line);
+ (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[(1) - (3)].interm).function->getMangledName().c_str());
+ (yyval.interm.intermNode)->getAsAggregate()->setType((yyvsp[(1) - (3)].interm).function->getReturnType());
+
+ // store the pragma information for debug and optimize and other vendor specific
+ // information. This information can be queried from the parse tree
+ (yyval.interm.intermNode)->getAsAggregate()->setOptimize(context->contextPragma.optimize);
+ (yyval.interm.intermNode)->getAsAggregate()->setDebug(context->contextPragma.debug);
+ (yyval.interm.intermNode)->getAsAggregate()->addToPragmaTable(context->contextPragma.pragmaTable);
+
+ if ((yyvsp[(3) - (3)].interm.intermNode) && (yyvsp[(3) - (3)].interm.intermNode)->getAsAggregate())
+ (yyval.interm.intermNode)->getAsAggregate()->setEndLine((yyvsp[(3) - (3)].interm.intermNode)->getAsAggregate()->getEndLine());
+ ;}
+ break;
+
+
+/* Line 1267 of yacc.c. */
+
+ default: break;
+ }
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (context, YY_("syntax error"));
+#else
+ {
+ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
+ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
+ {
+ YYSIZE_T yyalloc = 2 * yysize;
+ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
+ yyalloc = YYSTACK_ALLOC_MAXIMUM;
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yyalloc);
+ if (yymsg)
+ yymsg_alloc = yyalloc;
+ else
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ }
+ }
+
+ if (0 < yysize && yysize <= yymsg_alloc)
+ {
+ (void) yysyntax_error (yymsg, yystate, yychar);
+ yyerror (context, yymsg);
+ }
+ else
+ {
+ yyerror (context, YY_("syntax error"));
+ if (yysize != 0)
+ goto yyexhaustedlab;
+ }
+ }
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse look-ahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval, context);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse look-ahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (yyn != YYPACT_NINF)
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp, context);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ if (yyn == YYFINAL)
+ YYACCEPT;
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (context, YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEOF && yychar != YYEMPTY)
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval, context);
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp, context);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+
+
+
+int glslang_parse(TParseContext* context) {
+ return yyparse(context);
+}
+
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/glslang_tab.h b/Source/ThirdParty/ANGLE/src/compiler/glslang_tab.h
new file mode 100644
index 000000000..fa8480d3a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/glslang_tab.h
@@ -0,0 +1,274 @@
+/* A Bison parser, made by GNU Bison 2.3. */
+
+/* Skeleton interface for Bison's Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ INVARIANT = 258,
+ HIGH_PRECISION = 259,
+ MEDIUM_PRECISION = 260,
+ LOW_PRECISION = 261,
+ PRECISION = 262,
+ ATTRIBUTE = 263,
+ CONST_QUAL = 264,
+ BOOL_TYPE = 265,
+ FLOAT_TYPE = 266,
+ INT_TYPE = 267,
+ BREAK = 268,
+ CONTINUE = 269,
+ DO = 270,
+ ELSE = 271,
+ FOR = 272,
+ IF = 273,
+ DISCARD = 274,
+ RETURN = 275,
+ BVEC2 = 276,
+ BVEC3 = 277,
+ BVEC4 = 278,
+ IVEC2 = 279,
+ IVEC3 = 280,
+ IVEC4 = 281,
+ VEC2 = 282,
+ VEC3 = 283,
+ VEC4 = 284,
+ MATRIX2 = 285,
+ MATRIX3 = 286,
+ MATRIX4 = 287,
+ IN_QUAL = 288,
+ OUT_QUAL = 289,
+ INOUT_QUAL = 290,
+ UNIFORM = 291,
+ VARYING = 292,
+ STRUCT = 293,
+ VOID_TYPE = 294,
+ WHILE = 295,
+ SAMPLER2D = 296,
+ SAMPLERCUBE = 297,
+ IDENTIFIER = 298,
+ TYPE_NAME = 299,
+ FLOATCONSTANT = 300,
+ INTCONSTANT = 301,
+ BOOLCONSTANT = 302,
+ FIELD_SELECTION = 303,
+ LEFT_OP = 304,
+ RIGHT_OP = 305,
+ INC_OP = 306,
+ DEC_OP = 307,
+ LE_OP = 308,
+ GE_OP = 309,
+ EQ_OP = 310,
+ NE_OP = 311,
+ AND_OP = 312,
+ OR_OP = 313,
+ XOR_OP = 314,
+ MUL_ASSIGN = 315,
+ DIV_ASSIGN = 316,
+ ADD_ASSIGN = 317,
+ MOD_ASSIGN = 318,
+ LEFT_ASSIGN = 319,
+ RIGHT_ASSIGN = 320,
+ AND_ASSIGN = 321,
+ XOR_ASSIGN = 322,
+ OR_ASSIGN = 323,
+ SUB_ASSIGN = 324,
+ LEFT_PAREN = 325,
+ RIGHT_PAREN = 326,
+ LEFT_BRACKET = 327,
+ RIGHT_BRACKET = 328,
+ LEFT_BRACE = 329,
+ RIGHT_BRACE = 330,
+ DOT = 331,
+ COMMA = 332,
+ COLON = 333,
+ EQUAL = 334,
+ SEMICOLON = 335,
+ BANG = 336,
+ DASH = 337,
+ TILDE = 338,
+ PLUS = 339,
+ STAR = 340,
+ SLASH = 341,
+ PERCENT = 342,
+ LEFT_ANGLE = 343,
+ RIGHT_ANGLE = 344,
+ VERTICAL_BAR = 345,
+ CARET = 346,
+ AMPERSAND = 347,
+ QUESTION = 348
+ };
+#endif
+/* Tokens. */
+#define INVARIANT 258
+#define HIGH_PRECISION 259
+#define MEDIUM_PRECISION 260
+#define LOW_PRECISION 261
+#define PRECISION 262
+#define ATTRIBUTE 263
+#define CONST_QUAL 264
+#define BOOL_TYPE 265
+#define FLOAT_TYPE 266
+#define INT_TYPE 267
+#define BREAK 268
+#define CONTINUE 269
+#define DO 270
+#define ELSE 271
+#define FOR 272
+#define IF 273
+#define DISCARD 274
+#define RETURN 275
+#define BVEC2 276
+#define BVEC3 277
+#define BVEC4 278
+#define IVEC2 279
+#define IVEC3 280
+#define IVEC4 281
+#define VEC2 282
+#define VEC3 283
+#define VEC4 284
+#define MATRIX2 285
+#define MATRIX3 286
+#define MATRIX4 287
+#define IN_QUAL 288
+#define OUT_QUAL 289
+#define INOUT_QUAL 290
+#define UNIFORM 291
+#define VARYING 292
+#define STRUCT 293
+#define VOID_TYPE 294
+#define WHILE 295
+#define SAMPLER2D 296
+#define SAMPLERCUBE 297
+#define IDENTIFIER 298
+#define TYPE_NAME 299
+#define FLOATCONSTANT 300
+#define INTCONSTANT 301
+#define BOOLCONSTANT 302
+#define FIELD_SELECTION 303
+#define LEFT_OP 304
+#define RIGHT_OP 305
+#define INC_OP 306
+#define DEC_OP 307
+#define LE_OP 308
+#define GE_OP 309
+#define EQ_OP 310
+#define NE_OP 311
+#define AND_OP 312
+#define OR_OP 313
+#define XOR_OP 314
+#define MUL_ASSIGN 315
+#define DIV_ASSIGN 316
+#define ADD_ASSIGN 317
+#define MOD_ASSIGN 318
+#define LEFT_ASSIGN 319
+#define RIGHT_ASSIGN 320
+#define AND_ASSIGN 321
+#define XOR_ASSIGN 322
+#define OR_ASSIGN 323
+#define SUB_ASSIGN 324
+#define LEFT_PAREN 325
+#define RIGHT_PAREN 326
+#define LEFT_BRACKET 327
+#define RIGHT_BRACKET 328
+#define LEFT_BRACE 329
+#define RIGHT_BRACE 330
+#define DOT 331
+#define COMMA 332
+#define COLON 333
+#define EQUAL 334
+#define SEMICOLON 335
+#define BANG 336
+#define DASH 337
+#define TILDE 338
+#define PLUS 339
+#define STAR 340
+#define SLASH 341
+#define PERCENT 342
+#define LEFT_ANGLE 343
+#define RIGHT_ANGLE 344
+#define VERTICAL_BAR 345
+#define CARET 346
+#define AMPERSAND 347
+#define QUESTION 348
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+
+{
+ struct {
+ TSourceLoc line;
+ union {
+ TString *string;
+ float f;
+ int i;
+ bool b;
+ };
+ TSymbol* symbol;
+ } lex;
+ struct {
+ TSourceLoc line;
+ TOperator op;
+ union {
+ TIntermNode* intermNode;
+ TIntermNodePair nodePair;
+ TIntermTyped* intermTypedNode;
+ TIntermAggregate* intermAggregate;
+ };
+ union {
+ TPublicType type;
+ TPrecision precision;
+ TQualifier qualifier;
+ TFunction* function;
+ TParameter param;
+ TTypeLine typeLine;
+ TTypeList* typeList;
+ };
+ } interm;
+}
+/* Line 1529 of yacc.c. */
+
+ YYSTYPE;
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/intermOut.cpp b/Source/ThirdParty/ANGLE/src/compiler/intermOut.cpp
new file mode 100644
index 000000000..798a69af7
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/intermOut.cpp
@@ -0,0 +1,417 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/localintermediate.h"
+
+//
+// Two purposes:
+// 1. Show an example of how to iterate tree. Functions can
+// also directly call Traverse() on children themselves to
+// have finer grained control over the process than shown here.
+// See the last function for how to get started.
+// 2. Print out a text based description of the tree.
+//
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TOutputTraverser : public TIntermTraverser {
+public:
+ TOutputTraverser(TInfoSinkBase& i) : sink(i) { }
+ TInfoSinkBase& sink;
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+};
+
+TString TType::getCompleteString() const
+{
+ TStringStream stream;
+
+ if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+ stream << getQualifierString() << " " << getPrecisionString() << " ";
+ if (array)
+ stream << "array of ";
+ if (matrix)
+ stream << size << "X" << size << " matrix of ";
+ else if (size > 1)
+ stream << size << "-component vector of ";
+
+ stream << getBasicString();
+ return stream.str();
+}
+
+//
+// Helper functions for printing, not part of traversing.
+//
+
+void OutputTreeText(TInfoSinkBase& sink, TIntermNode* node, const int depth)
+{
+ int i;
+
+ sink.location(node->getLine());
+
+ for (i = 0; i < depth; ++i)
+ sink << " ";
+}
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TOutputTraverser::visitSymbol(TIntermSymbol* node)
+{
+ OutputTreeText(sink, node, depth);
+
+ sink << "'" << node->getSymbol() << "' ";
+ sink << "(" << node->getCompleteString() << ")\n";
+}
+
+bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpAssign: out << "move second child to first child"; break;
+ case EOpInitialize: out << "initialize first child with second child"; break;
+ case EOpAddAssign: out << "add second child into first child"; break;
+ case EOpSubAssign: out << "subtract second child into first child"; break;
+ case EOpMulAssign: out << "multiply second child into first child"; break;
+ case EOpVectorTimesMatrixAssign: out << "matrix mult second child into first child"; break;
+ case EOpVectorTimesScalarAssign: out << "vector scale second child into first child"; break;
+ case EOpMatrixTimesScalarAssign: out << "matrix scale second child into first child"; break;
+ case EOpMatrixTimesMatrixAssign: out << "matrix mult second child into first child"; break;
+ case EOpDivAssign: out << "divide second child into first child"; break;
+ case EOpIndexDirect: out << "direct index"; break;
+ case EOpIndexIndirect: out << "indirect index"; break;
+ case EOpIndexDirectStruct: out << "direct index for structure"; break;
+ case EOpVectorSwizzle: out << "vector swizzle"; break;
+
+ case EOpAdd: out << "add"; break;
+ case EOpSub: out << "subtract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+ case EOpDiv: out << "divide"; break;
+ case EOpEqual: out << "Compare Equal"; break;
+ case EOpNotEqual: out << "Compare Not Equal"; break;
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+
+ case EOpVectorTimesScalar: out << "vector-scale"; break;
+ case EOpVectorTimesMatrix: out << "vector-times-matrix"; break;
+ case EOpMatrixTimesVector: out << "matrix-times-vector"; break;
+ case EOpMatrixTimesScalar: out << "matrix-scale"; break;
+ case EOpMatrixTimesMatrix: out << "matrix-multiply"; break;
+
+ case EOpLogicalOr: out << "logical-or"; break;
+ case EOpLogicalXor: out << "logical-xor"; break;
+ case EOpLogicalAnd: out << "logical-and"; break;
+ default: out << "<unknown op>";
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpNegative: out << "Negate value"; break;
+ case EOpVectorLogicalNot:
+ case EOpLogicalNot: out << "Negate conditional"; break;
+
+ case EOpPostIncrement: out << "Post-Increment"; break;
+ case EOpPostDecrement: out << "Post-Decrement"; break;
+ case EOpPreIncrement: out << "Pre-Increment"; break;
+ case EOpPreDecrement: out << "Pre-Decrement"; break;
+
+ case EOpConvIntToBool: out << "Convert int to bool"; break;
+ case EOpConvFloatToBool:out << "Convert float to bool";break;
+ case EOpConvBoolToFloat:out << "Convert bool to float";break;
+ case EOpConvIntToFloat: out << "Convert int to float"; break;
+ case EOpConvFloatToInt: out << "Convert float to int"; break;
+ case EOpConvBoolToInt: out << "Convert bool to int"; break;
+
+ case EOpRadians: out << "radians"; break;
+ case EOpDegrees: out << "degrees"; break;
+ case EOpSin: out << "sine"; break;
+ case EOpCos: out << "cosine"; break;
+ case EOpTan: out << "tangent"; break;
+ case EOpAsin: out << "arc sine"; break;
+ case EOpAcos: out << "arc cosine"; break;
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpExp: out << "exp"; break;
+ case EOpLog: out << "log"; break;
+ case EOpExp2: out << "exp2"; break;
+ case EOpLog2: out << "log2"; break;
+ case EOpSqrt: out << "sqrt"; break;
+ case EOpInverseSqrt: out << "inverse sqrt"; break;
+
+ case EOpAbs: out << "Absolute value"; break;
+ case EOpSign: out << "Sign"; break;
+ case EOpFloor: out << "Floor"; break;
+ case EOpCeil: out << "Ceiling"; break;
+ case EOpFract: out << "Fraction"; break;
+
+ case EOpLength: out << "length"; break;
+ case EOpNormalize: out << "normalize"; break;
+ // case EOpDPdx: out << "dPdx"; break;
+ // case EOpDPdy: out << "dPdy"; break;
+ // case EOpFwidth: out << "fwidth"; break;
+
+ case EOpAny: out << "any"; break;
+ case EOpAll: out << "all"; break;
+
+ default: out.message(EPrefixError, "Bad unary op");
+ }
+
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ TInfoSinkBase& out = sink;
+
+ if (node->getOp() == EOpNull) {
+ out.message(EPrefixError, "node is still EOpNull!");
+ return true;
+ }
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getOp()) {
+ case EOpSequence: out << "Sequence\n"; return true;
+ case EOpComma: out << "Comma\n"; return true;
+ case EOpFunction: out << "Function Definition: " << node->getName(); break;
+ case EOpFunctionCall: out << "Function Call: " << node->getName(); break;
+ case EOpParameters: out << "Function Parameters: "; break;
+
+ case EOpConstructFloat: out << "Construct float"; break;
+ case EOpConstructVec2: out << "Construct vec2"; break;
+ case EOpConstructVec3: out << "Construct vec3"; break;
+ case EOpConstructVec4: out << "Construct vec4"; break;
+ case EOpConstructBool: out << "Construct bool"; break;
+ case EOpConstructBVec2: out << "Construct bvec2"; break;
+ case EOpConstructBVec3: out << "Construct bvec3"; break;
+ case EOpConstructBVec4: out << "Construct bvec4"; break;
+ case EOpConstructInt: out << "Construct int"; break;
+ case EOpConstructIVec2: out << "Construct ivec2"; break;
+ case EOpConstructIVec3: out << "Construct ivec3"; break;
+ case EOpConstructIVec4: out << "Construct ivec4"; break;
+ case EOpConstructMat2: out << "Construct mat2"; break;
+ case EOpConstructMat3: out << "Construct mat3"; break;
+ case EOpConstructMat4: out << "Construct mat4"; break;
+ case EOpConstructStruct: out << "Construct structure"; break;
+
+ case EOpLessThan: out << "Compare Less Than"; break;
+ case EOpGreaterThan: out << "Compare Greater Than"; break;
+ case EOpLessThanEqual: out << "Compare Less Than or Equal"; break;
+ case EOpGreaterThanEqual: out << "Compare Greater Than or Equal"; break;
+ case EOpVectorEqual: out << "Equal"; break;
+ case EOpVectorNotEqual: out << "NotEqual"; break;
+
+ case EOpMod: out << "mod"; break;
+ case EOpPow: out << "pow"; break;
+
+ case EOpAtan: out << "arc tangent"; break;
+
+ case EOpMin: out << "min"; break;
+ case EOpMax: out << "max"; break;
+ case EOpClamp: out << "clamp"; break;
+ case EOpMix: out << "mix"; break;
+ case EOpStep: out << "step"; break;
+ case EOpSmoothStep: out << "smoothstep"; break;
+
+ case EOpDistance: out << "distance"; break;
+ case EOpDot: out << "dot-product"; break;
+ case EOpCross: out << "cross-product"; break;
+ case EOpFaceForward: out << "face-forward"; break;
+ case EOpReflect: out << "reflect"; break;
+ case EOpRefract: out << "refract"; break;
+ case EOpMul: out << "component-wise multiply"; break;
+
+ default: out.message(EPrefixError, "Bad aggregation op");
+ }
+
+ if (node->getOp() != EOpSequence && node->getOp() != EOpParameters)
+ out << " (" << node->getCompleteString() << ")";
+
+ out << "\n";
+
+ return true;
+}
+
+bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ out << "Test condition and select";
+ out << " (" << node->getCompleteString() << ")\n";
+
+ ++depth;
+
+ OutputTreeText(sink, node, depth);
+ out << "Condition\n";
+ node->getCondition()->traverse(this);
+
+ OutputTreeText(sink, node, depth);
+ if (node->getTrueBlock()) {
+ out << "true case\n";
+ node->getTrueBlock()->traverse(this);
+ } else
+ out << "true case is null\n";
+
+ if (node->getFalseBlock()) {
+ OutputTreeText(sink, node, depth);
+ out << "false case\n";
+ node->getFalseBlock()->traverse(this);
+ }
+
+ --depth;
+
+ return false;
+}
+
+void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+ TInfoSinkBase& out = sink;
+
+ int size = node->getType().getObjectSize();
+
+ for (int i = 0; i < size; i++) {
+ OutputTreeText(out, node, depth);
+ switch (node->getUnionArrayPointer()[i].getType()) {
+ case EbtBool:
+ if (node->getUnionArrayPointer()[i].getBConst())
+ out << "true";
+ else
+ out << "false";
+
+ out << " (" << "const bool" << ")";
+ out << "\n";
+ break;
+ case EbtFloat:
+ out << node->getUnionArrayPointer()[i].getFConst();
+ out << " (const float)\n";
+ break;
+ case EbtInt:
+ out << node->getUnionArrayPointer()[i].getIConst();
+ out << " (const int)\n";
+ break;
+ default:
+ out.message(EPrefixInternalError, "Unknown constant", node->getLine());
+ break;
+ }
+ }
+}
+
+bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ out << "Loop with condition ";
+ if (node->getType() == ELoopDoWhile)
+ out << "not ";
+ out << "tested first\n";
+
+ ++depth;
+
+ OutputTreeText(sink, node, depth);
+ if (node->getCondition()) {
+ out << "Loop Condition\n";
+ node->getCondition()->traverse(this);
+ } else
+ out << "No loop condition\n";
+
+ OutputTreeText(sink, node, depth);
+ if (node->getBody()) {
+ out << "Loop Body\n";
+ node->getBody()->traverse(this);
+ } else
+ out << "No loop body\n";
+
+ if (node->getExpression()) {
+ OutputTreeText(sink, node, depth);
+ out << "Loop Terminal Expression\n";
+ node->getExpression()->traverse(this);
+ }
+
+ --depth;
+
+ return false;
+}
+
+bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node)
+{
+ TInfoSinkBase& out = sink;
+
+ OutputTreeText(out, node, depth);
+
+ switch (node->getFlowOp()) {
+ case EOpKill: out << "Branch: Kill"; break;
+ case EOpBreak: out << "Branch: Break"; break;
+ case EOpContinue: out << "Branch: Continue"; break;
+ case EOpReturn: out << "Branch: Return"; break;
+ default: out << "Branch: Unknown Branch"; break;
+ }
+
+ if (node->getExpression()) {
+ out << " with expression\n";
+ ++depth;
+ node->getExpression()->traverse(this);
+ --depth;
+ } else
+ out << "\n";
+
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. It's children will still be processed.
+//
+void TIntermediate::outputTree(TIntermNode* root)
+{
+ if (root == 0)
+ return;
+
+ TOutputTraverser it(infoSink.info);
+
+ root->traverse(&it);
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/intermediate.h b/Source/ThirdParty/ANGLE/src/compiler/intermediate.h
new file mode 100644
index 000000000..a8af5ab06
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/intermediate.h
@@ -0,0 +1,544 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// Definition of the in-memory high-level intermediate representation
+// of shaders. This is a tree that parser creates.
+//
+// Nodes in the tree are defined as a hierarchy of classes derived from
+// TIntermNode. Each is a node in a tree. There is no preset branching factor;
+// each node can have it's own type of list of children.
+//
+
+#ifndef __INTERMEDIATE_H
+#define __INTERMEDIATE_H
+
+#include "compiler/Common.h"
+#include "compiler/Types.h"
+#include "compiler/ConstantUnion.h"
+
+//
+// Operators used by the high-level (parse tree) representation.
+//
+enum TOperator {
+ EOpNull, // if in a node, should only mean a node is still being built
+ EOpSequence, // denotes a list of statements, or parameters, etc.
+ EOpFunctionCall,
+ EOpFunction, // For function definition
+ EOpParameters, // an aggregate listing the parameters to a function
+
+ EOpDeclaration,
+ EOpPrototype,
+
+ //
+ // Unary operators
+ //
+
+ EOpNegative,
+ EOpLogicalNot,
+ EOpVectorLogicalNot,
+
+ EOpPostIncrement,
+ EOpPostDecrement,
+ EOpPreIncrement,
+ EOpPreDecrement,
+
+ EOpConvIntToBool,
+ EOpConvFloatToBool,
+ EOpConvBoolToFloat,
+ EOpConvIntToFloat,
+ EOpConvFloatToInt,
+ EOpConvBoolToInt,
+
+ //
+ // binary operations
+ //
+
+ EOpAdd,
+ EOpSub,
+ EOpMul,
+ EOpDiv,
+ EOpEqual,
+ EOpNotEqual,
+ EOpVectorEqual,
+ EOpVectorNotEqual,
+ EOpLessThan,
+ EOpGreaterThan,
+ EOpLessThanEqual,
+ EOpGreaterThanEqual,
+ EOpComma,
+
+ EOpVectorTimesScalar,
+ EOpVectorTimesMatrix,
+ EOpMatrixTimesVector,
+ EOpMatrixTimesScalar,
+
+ EOpLogicalOr,
+ EOpLogicalXor,
+ EOpLogicalAnd,
+
+ EOpIndexDirect,
+ EOpIndexIndirect,
+ EOpIndexDirectStruct,
+
+ EOpVectorSwizzle,
+
+ //
+ // Built-in functions potentially mapped to operators
+ //
+
+ EOpRadians,
+ EOpDegrees,
+ EOpSin,
+ EOpCos,
+ EOpTan,
+ EOpAsin,
+ EOpAcos,
+ EOpAtan,
+
+ EOpPow,
+ EOpExp,
+ EOpLog,
+ EOpExp2,
+ EOpLog2,
+ EOpSqrt,
+ EOpInverseSqrt,
+
+ EOpAbs,
+ EOpSign,
+ EOpFloor,
+ EOpCeil,
+ EOpFract,
+ EOpMod,
+ EOpMin,
+ EOpMax,
+ EOpClamp,
+ EOpMix,
+ EOpStep,
+ EOpSmoothStep,
+
+ EOpLength,
+ EOpDistance,
+ EOpDot,
+ EOpCross,
+ EOpNormalize,
+ EOpFaceForward,
+ EOpReflect,
+ EOpRefract,
+
+ EOpDFdx, // Fragment only, OES_standard_derivatives extension
+ EOpDFdy, // Fragment only, OES_standard_derivatives extension
+ EOpFwidth, // Fragment only, OES_standard_derivatives extension
+
+ EOpMatrixTimesMatrix,
+
+ EOpAny,
+ EOpAll,
+
+ //
+ // Branch
+ //
+
+ EOpKill, // Fragment only
+ EOpReturn,
+ EOpBreak,
+ EOpContinue,
+
+ //
+ // Constructors
+ //
+
+ EOpConstructInt,
+ EOpConstructBool,
+ EOpConstructFloat,
+ EOpConstructVec2,
+ EOpConstructVec3,
+ EOpConstructVec4,
+ EOpConstructBVec2,
+ EOpConstructBVec3,
+ EOpConstructBVec4,
+ EOpConstructIVec2,
+ EOpConstructIVec3,
+ EOpConstructIVec4,
+ EOpConstructMat2,
+ EOpConstructMat3,
+ EOpConstructMat4,
+ EOpConstructStruct,
+
+ //
+ // moves
+ //
+
+ EOpAssign,
+ EOpInitialize,
+ EOpAddAssign,
+ EOpSubAssign,
+ EOpMulAssign,
+ EOpVectorTimesMatrixAssign,
+ EOpVectorTimesScalarAssign,
+ EOpMatrixTimesScalarAssign,
+ EOpMatrixTimesMatrixAssign,
+ EOpDivAssign,
+};
+
+extern const char* getOperatorString(TOperator op);
+
+class TIntermTraverser;
+class TIntermAggregate;
+class TIntermBinary;
+class TIntermUnary;
+class TIntermConstantUnion;
+class TIntermSelection;
+class TIntermTyped;
+class TIntermSymbol;
+class TIntermLoop;
+class TInfoSink;
+
+//
+// Base class for the tree nodes
+//
+class TIntermNode {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+
+ TIntermNode() : line(0) {}
+
+ TSourceLoc getLine() const { return line; }
+ void setLine(TSourceLoc l) { line = l; }
+
+ virtual void traverse(TIntermTraverser*) = 0;
+ virtual TIntermTyped* getAsTyped() { return 0; }
+ virtual TIntermConstantUnion* getAsConstantUnion() { return 0; }
+ virtual TIntermAggregate* getAsAggregate() { return 0; }
+ virtual TIntermBinary* getAsBinaryNode() { return 0; }
+ virtual TIntermUnary* getAsUnaryNode() { return 0; }
+ virtual TIntermSelection* getAsSelectionNode() { return 0; }
+ virtual TIntermSymbol* getAsSymbolNode() { return 0; }
+ virtual TIntermLoop* getAsLoopNode() { return 0; }
+ virtual ~TIntermNode() { }
+
+protected:
+ TSourceLoc line;
+};
+
+//
+// This is just to help yacc.
+//
+struct TIntermNodePair {
+ TIntermNode* node1;
+ TIntermNode* node2;
+};
+
+//
+// Intermediate class for nodes that have a type.
+//
+class TIntermTyped : public TIntermNode {
+public:
+ TIntermTyped(const TType& t) : type(t) { }
+ virtual TIntermTyped* getAsTyped() { return this; }
+
+ void setType(const TType& t) { type = t; }
+ const TType& getType() const { return type; }
+ TType* getTypePointer() { return &type; }
+
+ TBasicType getBasicType() const { return type.getBasicType(); }
+ TQualifier getQualifier() const { return type.getQualifier(); }
+ TPrecision getPrecision() const { return type.getPrecision(); }
+ int getNominalSize() const { return type.getNominalSize(); }
+
+ bool isMatrix() const { return type.isMatrix(); }
+ bool isArray() const { return type.isArray(); }
+ bool isVector() const { return type.isVector(); }
+ bool isScalar() const { return type.isScalar(); }
+ const char* getBasicString() const { return type.getBasicString(); }
+ const char* getQualifierString() const { return type.getQualifierString(); }
+ TString getCompleteString() const { return type.getCompleteString(); }
+
+protected:
+ TType type;
+};
+
+//
+// Handle for, do-while, and while loops.
+//
+enum TLoopType {
+ ELoopFor,
+ ELoopWhile,
+ ELoopDoWhile,
+};
+
+class TIntermLoop : public TIntermNode {
+public:
+ TIntermLoop(TLoopType aType,
+ TIntermNode *aInit, TIntermTyped* aCond, TIntermTyped* aExpr,
+ TIntermNode* aBody) :
+ type(aType),
+ init(aInit),
+ cond(aCond),
+ expr(aExpr),
+ body(aBody),
+ unrollFlag(false) { }
+
+ virtual TIntermLoop* getAsLoopNode() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TLoopType getType() const { return type; }
+ TIntermNode* getInit() { return init; }
+ TIntermTyped* getCondition() { return cond; }
+ TIntermTyped* getExpression() { return expr; }
+ TIntermNode* getBody() { return body; }
+
+ void setUnrollFlag(bool flag) { unrollFlag = flag; }
+ bool getUnrollFlag() { return unrollFlag; }
+
+protected:
+ TLoopType type;
+ TIntermNode* init; // for-loop initialization
+ TIntermTyped* cond; // loop exit condition
+ TIntermTyped* expr; // for-loop expression
+ TIntermNode* body; // loop body
+
+ bool unrollFlag; // Whether the loop should be unrolled or not.
+};
+
+//
+// Handle break, continue, return, and kill.
+//
+class TIntermBranch : public TIntermNode {
+public:
+ TIntermBranch(TOperator op, TIntermTyped* e) :
+ flowOp(op),
+ expression(e) { }
+
+ virtual void traverse(TIntermTraverser*);
+
+ TOperator getFlowOp() { return flowOp; }
+ TIntermTyped* getExpression() { return expression; }
+
+protected:
+ TOperator flowOp;
+ TIntermTyped* expression; // non-zero except for "return exp;" statements
+};
+
+//
+// Nodes that correspond to symbols or constants in the source code.
+//
+class TIntermSymbol : public TIntermTyped {
+public:
+ // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from
+ // per process globalpoolallocator, then it causes increased memory usage per compile
+ // it is essential to use "symbol = sym" to assign to symbol
+ TIntermSymbol(int i, const TString& sym, const TType& t) :
+ TIntermTyped(t), id(i) { symbol = sym; originalSymbol = sym; }
+
+ int getId() const { return id; }
+ const TString& getSymbol() const { return symbol; }
+
+ void setId(int newId) { id = newId; }
+ void setSymbol(const TString& sym) { symbol = sym; }
+
+ const TString& getOriginalSymbol() const { return originalSymbol; }
+
+ virtual void traverse(TIntermTraverser*);
+ virtual TIntermSymbol* getAsSymbolNode() { return this; }
+
+protected:
+ int id;
+ TString symbol;
+ TString originalSymbol;
+};
+
+class TIntermConstantUnion : public TIntermTyped {
+public:
+ TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
+
+ ConstantUnion* getUnionArrayPointer() const { return unionArrayPointer; }
+ void setUnionArrayPointer(ConstantUnion *c) { unionArrayPointer = c; }
+
+ virtual TIntermConstantUnion* getAsConstantUnion() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&);
+
+protected:
+ ConstantUnion *unionArrayPointer;
+};
+
+//
+// Intermediate class for node types that hold operators.
+//
+class TIntermOperator : public TIntermTyped {
+public:
+ TOperator getOp() const { return op; }
+ void setOp(TOperator o) { op = o; }
+
+ bool modifiesState() const;
+ bool isConstructor() const;
+
+protected:
+ TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat, EbpUndefined)), op(o) {}
+ TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {}
+ TOperator op;
+};
+
+//
+// Nodes for all the basic binary math operators.
+//
+class TIntermBinary : public TIntermOperator {
+public:
+ TIntermBinary(TOperator o) : TIntermOperator(o) {}
+
+ virtual TIntermBinary* getAsBinaryNode() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ void setLeft(TIntermTyped* n) { left = n; }
+ void setRight(TIntermTyped* n) { right = n; }
+ TIntermTyped* getLeft() const { return left; }
+ TIntermTyped* getRight() const { return right; }
+ bool promote(TInfoSink&);
+
+protected:
+ TIntermTyped* left;
+ TIntermTyped* right;
+};
+
+//
+// Nodes for unary math operators.
+//
+class TIntermUnary : public TIntermOperator {
+public:
+ TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0) {}
+ TIntermUnary(TOperator o) : TIntermOperator(o), operand(0) {}
+
+ virtual void traverse(TIntermTraverser*);
+ virtual TIntermUnary* getAsUnaryNode() { return this; }
+
+ void setOperand(TIntermTyped* o) { operand = o; }
+ TIntermTyped* getOperand() { return operand; }
+ bool promote(TInfoSink&);
+
+protected:
+ TIntermTyped* operand;
+};
+
+typedef TVector<TIntermNode*> TIntermSequence;
+typedef TVector<int> TQualifierList;
+typedef TMap<TString, TString> TPragmaTable;
+//
+// Nodes that operate on an arbitrary sized set of children.
+//
+class TIntermAggregate : public TIntermOperator {
+public:
+ TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(0), endLine(0) { }
+ TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(0) { }
+ ~TIntermAggregate() { delete pragmaTable; }
+
+ virtual TIntermAggregate* getAsAggregate() { return this; }
+ virtual void traverse(TIntermTraverser*);
+
+ TIntermSequence& getSequence() { return sequence; }
+
+ void setName(const TString& n) { name = n; }
+ const TString& getName() const { return name; }
+
+ void setUserDefined() { userDefined = true; }
+ bool isUserDefined() { return userDefined; }
+
+ void setOptimize(bool o) { optimize = o; }
+ bool getOptimize() { return optimize; }
+ void setDebug(bool d) { debug = d; }
+ bool getDebug() { return debug; }
+ void addToPragmaTable(const TPragmaTable& pTable);
+ const TPragmaTable& getPragmaTable() const { return *pragmaTable; }
+ void setEndLine(TSourceLoc line) { endLine = line; }
+ TSourceLoc getEndLine() const { return endLine; }
+
+protected:
+ TIntermAggregate(const TIntermAggregate&); // disallow copy constructor
+ TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator
+ TIntermSequence sequence;
+ TString name;
+ bool userDefined; // used for user defined function names
+
+ bool optimize;
+ bool debug;
+ TPragmaTable *pragmaTable;
+ TSourceLoc endLine;
+};
+
+//
+// For if tests. Simplified since there is no switch statement.
+//
+class TIntermSelection : public TIntermTyped {
+public:
+ TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) :
+ TIntermTyped(TType(EbtVoid, EbpUndefined)), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+ TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) :
+ TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {}
+
+ virtual void traverse(TIntermTraverser*);
+
+ bool usesTernaryOperator() const { return getBasicType() != EbtVoid; }
+ TIntermNode* getCondition() const { return condition; }
+ TIntermNode* getTrueBlock() const { return trueBlock; }
+ TIntermNode* getFalseBlock() const { return falseBlock; }
+ TIntermSelection* getAsSelectionNode() { return this; }
+
+protected:
+ TIntermTyped* condition;
+ TIntermNode* trueBlock;
+ TIntermNode* falseBlock;
+};
+
+enum Visit
+{
+ PreVisit,
+ InVisit,
+ PostVisit
+};
+
+//
+// For traversing the tree. User should derive from this,
+// put their traversal specific data in it, and then pass
+// it to a Traverse method.
+//
+// When using this, just fill in the methods for nodes you want visited.
+// Return false from a pre-visit to skip visiting that node's subtree.
+//
+class TIntermTraverser
+{
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+
+ TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) :
+ preVisit(preVisit),
+ inVisit(inVisit),
+ postVisit(postVisit),
+ rightToLeft(rightToLeft),
+ depth(0) {}
+
+ virtual void visitSymbol(TIntermSymbol*) {}
+ virtual void visitConstantUnion(TIntermConstantUnion*) {}
+ virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
+ virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}
+ virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;}
+ virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;}
+ virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;}
+ virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;}
+
+ void incrementDepth() {depth++;}
+ void decrementDepth() {depth--;}
+
+ const bool preVisit;
+ const bool inVisit;
+ const bool postVisit;
+ const bool rightToLeft;
+
+protected:
+ int depth;
+};
+
+#endif // __INTERMEDIATE_H
diff --git a/Source/ThirdParty/ANGLE/src/compiler/localintermediate.h b/Source/ThirdParty/ANGLE/src/compiler/localintermediate.h
new file mode 100644
index 000000000..56890bd56
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/localintermediate.h
@@ -0,0 +1,58 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef _LOCAL_INTERMEDIATE_INCLUDED_
+#define _LOCAL_INTERMEDIATE_INCLUDED_
+
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/intermediate.h"
+#include "compiler/SymbolTable.h"
+
+struct TVectorFields {
+ int offsets[4];
+ int num;
+};
+
+//
+// Set of helper functions to help parse and build the tree.
+//
+class TInfoSink;
+class TIntermediate {
+public:
+ POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
+
+ TIntermediate(TInfoSink& i) : infoSink(i) { }
+ TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc);
+ TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
+ TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, TSymbolTable&);
+ TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
+ TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
+ TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, TSourceLoc, TSymbolTable&);
+ TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc);
+ TIntermAggregate* makeAggregate(TIntermNode* node, TSourceLoc);
+ TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc);
+ TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc);
+ TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc);
+ TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc);
+ TIntermConstantUnion* addConstantUnion(ConstantUnion*, const TType&, TSourceLoc);
+ TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
+ bool parseConstTree(TSourceLoc, TIntermNode*, ConstantUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false);
+ TIntermNode* addLoop(TLoopType, TIntermNode*, TIntermTyped*, TIntermTyped*, TIntermNode*, TSourceLoc);
+ TIntermBranch* addBranch(TOperator, TSourceLoc);
+ TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc);
+ TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc);
+ bool postProcess(TIntermNode*);
+ void remove(TIntermNode*);
+ void outputTree(TIntermNode*);
+
+protected:
+ TInfoSink& infoSink;
+
+private:
+ void operator=(TIntermediate&); // prevent assignments
+};
+
+#endif // _LOCAL_INTERMEDIATE_INCLUDED_
diff --git a/Source/ThirdParty/ANGLE/src/compiler/osinclude.h b/Source/ThirdParty/ANGLE/src/compiler/osinclude.h
new file mode 100644
index 000000000..1af5064b0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/osinclude.h
@@ -0,0 +1,70 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef __OSINCLUDE_H
+#define __OSINCLUDE_H
+
+//
+// This file contains contains os-specific datatypes and
+// declares any os-specific functions.
+//
+
+#if defined(_WIN32) || defined(_WIN64)
+#define ANGLE_OS_WIN
+#elif defined(__APPLE__) || defined(__linux__) || \
+ defined(__FreeBSD__) || defined(__OpenBSD__) || \
+ defined(__sun)
+#define ANGLE_OS_POSIX
+#else
+#error Unsupported platform.
+#endif
+
+#if defined(ANGLE_USE_NSPR)
+#include "prthread.h"
+#elif defined(ANGLE_OS_WIN)
+#define STRICT
+#define VC_EXTRALEAN 1
+#include <windows.h>
+#elif defined(ANGLE_OS_POSIX)
+#include <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+#endif // ANGLE_USE_NSPR
+
+
+#include "compiler/debug.h"
+
+//
+// Thread Local Storage Operations
+//
+#if defined(ANGLE_USE_NSPR)
+typedef PRUintn OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX 0xFFFFFFFF
+#elif defined(ANGLE_OS_WIN)
+typedef DWORD OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES)
+#elif defined(ANGLE_OS_POSIX)
+typedef unsigned int OS_TLSIndex;
+#define OS_INVALID_TLS_INDEX 0xFFFFFFFF
+#endif // ANGLE_USE_NSPR
+
+OS_TLSIndex OS_AllocTLSIndex();
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue);
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex);
+
+inline void* OS_GetTLSValue(OS_TLSIndex nIndex)
+{
+ ASSERT(nIndex != OS_INVALID_TLS_INDEX);
+#if defined(ANGLE_USE_NSPR)
+ return PR_GetThreadPrivate(nIndex);
+#elif defined(ANGLE_OS_WIN)
+ return TlsGetValue(nIndex);
+#elif defined(ANGLE_OS_POSIX)
+ return pthread_getspecific(nIndex);
+#endif // ANGLE_OS_WIN
+}
+
+#endif // __OSINCLUDE_H
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ossource_nspr.cpp b/Source/ThirdParty/ANGLE/src/compiler/ossource_nspr.cpp
new file mode 100644
index 000000000..f63d81e5d
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ossource_nspr.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// This file contains the nspr specific functions
+//
+#include "compiler/osinclude.h"
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ PRUintn index;
+ PRStatus status = PR_NewThreadPrivateIndex(&index, NULL);
+
+ if (status) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return OS_INVALID_TLS_INDEX;
+ }
+
+ return index;
+}
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ return PR_SetThreadPrivate(nIndex, lpvValue) == 0;
+}
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ // Can't delete TLS keys with nspr
+ return true;
+}
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ossource_posix.cpp b/Source/ThirdParty/ANGLE/src/compiler/ossource_posix.cpp
new file mode 100644
index 000000000..a21b0c23c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ossource_posix.cpp
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//
+// This file contains the posix specific functions
+//
+#include "compiler/osinclude.h"
+
+#if !defined(ANGLE_OS_POSIX)
+#error Trying to build a posix specific file in a non-posix build.
+#endif
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ pthread_key_t pPoolIndex;
+
+ //
+ // Create global pool key.
+ //
+ if ((pthread_key_create(&pPoolIndex, NULL)) != 0) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return false;
+ }
+ return pPoolIndex;
+}
+
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (pthread_setspecific(nIndex, lpvValue) == 0)
+ return true;
+ return false;
+}
+
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ //
+ // Delete the global pool key.
+ //
+ if (pthread_key_delete(nIndex) == 0)
+ return true;
+ return false;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/ossource_win.cpp b/Source/ThirdParty/ANGLE/src/compiler/ossource_win.cpp
new file mode 100644
index 000000000..89922fef3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/ossource_win.cpp
@@ -0,0 +1,57 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/osinclude.h"
+//
+// This file contains contains the window's specific functions
+//
+
+#if !defined(ANGLE_OS_WIN)
+#error Trying to build a windows specific file in a non windows build.
+#endif
+
+
+//
+// Thread Local Storage Operations
+//
+OS_TLSIndex OS_AllocTLSIndex()
+{
+ DWORD dwIndex = TlsAlloc();
+ if (dwIndex == TLS_OUT_OF_INDEXES) {
+ assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage");
+ return OS_INVALID_TLS_INDEX;
+ }
+
+ return dwIndex;
+}
+
+
+bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (TlsSetValue(nIndex, lpvValue))
+ return true;
+ else
+ return false;
+}
+
+
+bool OS_FreeTLSIndex(OS_TLSIndex nIndex)
+{
+ if (nIndex == OS_INVALID_TLS_INDEX) {
+ assert(0 && "OS_SetTLSValue(): Invalid TLS Index");
+ return false;
+ }
+
+ if (TlsFree(nIndex))
+ return true;
+ else
+ return false;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/parseConst.cpp b/Source/ThirdParty/ANGLE/src/compiler/parseConst.cpp
new file mode 100644
index 000000000..9a8a50c31
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/parseConst.cpp
@@ -0,0 +1,238 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/ParseHelper.h"
+
+//
+// Use this class to carry along data from node to node in
+// the traversal
+//
+class TConstTraverser : public TIntermTraverser {
+public:
+ TConstTraverser(ConstantUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t)
+ : error(false),
+ index(0),
+ unionArray(cUnion),
+ type(t),
+ constructorType(constructType),
+ singleConstantParam(singleConstParam),
+ infoSink(sink),
+ symbolTable(symTable),
+ size(0),
+ isMatrix(false),
+ matrixSize(0) {
+ }
+
+ bool error;
+
+protected:
+ void visitSymbol(TIntermSymbol*);
+ void visitConstantUnion(TIntermConstantUnion*);
+ bool visitBinary(Visit visit, TIntermBinary*);
+ bool visitUnary(Visit visit, TIntermUnary*);
+ bool visitSelection(Visit visit, TIntermSelection*);
+ bool visitAggregate(Visit visit, TIntermAggregate*);
+ bool visitLoop(Visit visit, TIntermLoop*);
+ bool visitBranch(Visit visit, TIntermBranch*);
+
+ int index;
+ ConstantUnion *unionArray;
+ TType type;
+ TOperator constructorType;
+ bool singleConstantParam;
+ TInfoSink& infoSink;
+ TSymbolTable& symbolTable;
+ int size; // size of the constructor ( 4 for vec4)
+ bool isMatrix;
+ int matrixSize; // dimension of the matrix (nominal size and not the instance size)
+};
+
+//
+// The rest of the file are the traversal functions. The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children. If you process children yourself,
+// return false.
+//
+
+void TConstTraverser::visitSymbol(TIntermSymbol* node)
+{
+ infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine());
+ return;
+
+}
+
+bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node)
+{
+ TQualifier qualifier = node->getType().getQualifier();
+
+ if (qualifier != EvqConst) {
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
+ error = true;
+ return false;
+ }
+
+ infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine());
+
+ return false;
+}
+
+bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node)
+{
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
+ error = true;
+ return false;
+}
+
+bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node)
+{
+ if (!node->isConstructor() && node->getOp() != EOpComma) {
+ TString buf;
+ buf.append("'constructor' : assigning non-constant to ");
+ buf.append(type.getCompleteString());
+ infoSink.info.message(EPrefixError, buf.c_str(), node->getLine());
+ error = true;
+ return false;
+ }
+
+ if (node->getSequence().size() == 0) {
+ error = true;
+ return false;
+ }
+
+ bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion();
+ if (flag)
+ {
+ singleConstantParam = true;
+ constructorType = node->getOp();
+ size = node->getType().getObjectSize();
+
+ if (node->getType().isMatrix()) {
+ isMatrix = true;
+ matrixSize = node->getType().getNominalSize();
+ }
+ }
+
+ for (TIntermSequence::iterator p = node->getSequence().begin();
+ p != node->getSequence().end(); p++) {
+
+ if (node->getOp() == EOpComma)
+ index = 0;
+
+ (*p)->traverse(this);
+ }
+ if (flag)
+ {
+ singleConstantParam = false;
+ constructorType = EOpNull;
+ size = 0;
+ isMatrix = false;
+ matrixSize = 0;
+ }
+ return false;
+}
+
+bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node)
+{
+ infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine());
+ error = true;
+ return false;
+}
+
+void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node)
+{
+ ConstantUnion* leftUnionArray = unionArray;
+ int instanceSize = type.getObjectSize();
+
+ if (index >= instanceSize)
+ return;
+
+ if (!singleConstantParam) {
+ int size = node->getType().getObjectSize();
+
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ for (int i=0; i < size; i++) {
+ if (index >= instanceSize)
+ return;
+ leftUnionArray[index] = rightUnionArray[i];
+
+ (index)++;
+ }
+ } else {
+ int totalSize = index + size;
+ ConstantUnion *rightUnionArray = node->getUnionArrayPointer();
+ if (!isMatrix) {
+ int count = 0;
+ for (int i = index; i < totalSize; i++) {
+ if (i >= instanceSize)
+ return;
+
+ leftUnionArray[i] = rightUnionArray[count];
+
+ (index)++;
+
+ if (node->getType().getObjectSize() > 1)
+ count++;
+ }
+ } else { // for matrix constructors
+ int count = 0;
+ int element = index;
+ for (int i = index; i < totalSize; i++) {
+ if (i >= instanceSize)
+ return;
+ if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 )
+ leftUnionArray[i] = rightUnionArray[count];
+ else
+ leftUnionArray[i].setFConst(0.0f);
+
+ (index)++;
+
+ if (node->getType().getObjectSize() > 1)
+ count++;
+ }
+ }
+ }
+}
+
+bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node)
+{
+ infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine());
+ error = true;
+ return false;
+}
+
+bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node)
+{
+ infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine());
+ error = true;
+ return false;
+}
+
+//
+// This function is the one to call externally to start the traversal.
+// Individual functions can be initialized to 0 to skip processing of that
+// type of node. It's children will still be processed.
+//
+bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, ConstantUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam)
+{
+ if (root == 0)
+ return false;
+
+ TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t);
+
+ root->traverse(&it);
+ if (it.error)
+ return true;
+ else
+ return false;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/atom.c b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/atom.c
new file mode 100644
index 000000000..b4a7761ae
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/atom.c
@@ -0,0 +1,736 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+//
+// atom.c
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "compiler/debug.h"
+#include "compiler/preprocessor/slglobals.h"
+
+#undef malloc
+#undef realloc
+#undef free
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////// String table: //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static const struct {
+ int val;
+ const char *str;
+} tokens[] = {
+ { CPP_AND_OP, "&&" },
+ { CPP_AND_ASSIGN, "&=" },
+ { CPP_SUB_ASSIGN, "-=" },
+ { CPP_MOD_ASSIGN, "%=" },
+ { CPP_ADD_ASSIGN, "+=" },
+ { CPP_DIV_ASSIGN, "/=" },
+ { CPP_MUL_ASSIGN, "*=" },
+ { CPP_RIGHT_BRACKET, ":>" },
+ { CPP_EQ_OP, "==" },
+ { CPP_XOR_OP, "^^" },
+ { CPP_XOR_ASSIGN, "^=" },
+ { CPP_FLOATCONSTANT, "<float-const>" },
+ { CPP_GE_OP, ">=" },
+ { CPP_RIGHT_OP, ">>" },
+ { CPP_RIGHT_ASSIGN, ">>=" },
+ { CPP_IDENTIFIER, "<ident>" },
+ { CPP_INTCONSTANT, "<int-const>" },
+ { CPP_LE_OP, "<=" },
+ { CPP_LEFT_OP, "<<" },
+ { CPP_LEFT_ASSIGN, "<<=" },
+ { CPP_LEFT_BRACKET, "<:" },
+ { CPP_LEFT_BRACE, "<%" },
+ { CPP_DEC_OP, "--" },
+ { CPP_RIGHT_BRACE, "%>" },
+ { CPP_NE_OP, "!=" },
+ { CPP_OR_OP, "||" },
+ { CPP_OR_ASSIGN, "|=" },
+ { CPP_INC_OP, "++" },
+ { CPP_STRCONSTANT, "<string-const>" },
+ { CPP_TYPEIDENTIFIER, "<type-ident>" },
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////// String table: //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#define INIT_STRING_TABLE_SIZE 16384
+
+typedef struct StringTable_Rec {
+ char *strings;
+ int nextFree;
+ int size;
+} StringTable;
+
+/*
+ * InitStringTable() - Initialize the string table.
+ *
+ */
+
+static int InitStringTable(StringTable *stable)
+{
+ stable->strings = (char *) malloc(INIT_STRING_TABLE_SIZE);
+ if (!stable->strings)
+ return 0;
+ // Zero-th offset means "empty" so don't use it.
+ stable->nextFree = 1;
+ stable->size = INIT_STRING_TABLE_SIZE;
+ return 1;
+} // InitStringTable
+
+/*
+ * FreeStringTable() - Free the string table.
+ *
+ */
+
+static void FreeStringTable(StringTable *stable)
+{
+ if (stable->strings)
+ free(stable->strings);
+ stable->strings = NULL;
+ stable->nextFree = 0;
+ stable->size = 0;
+} // FreeStringTable
+
+/*
+ * HashString() - Hash a string with the base hash function.
+ *
+ */
+
+static int HashString(const char *s)
+{
+ int hval = 0;
+
+ while (*s) {
+ hval = (hval*13507 + *s*197) ^ (hval >> 2);
+ s++;
+ }
+ return hval & 0x7fffffff;
+} // HashString
+
+/*
+ * HashString2() - Hash a string with the incrimenting hash function.
+ *
+ */
+
+static int HashString2(const char *s)
+{
+ int hval = 0;
+
+ while (*s) {
+ hval = (hval*729 + *s*37) ^ (hval >> 1);
+ s++;
+ }
+ return hval;
+} // HashString2
+
+/*
+ * AddString() - Add a string to a string table. Return it's offset.
+ *
+ */
+
+static int AddString(StringTable *stable, const char *s)
+{
+ int len, loc;
+ char *str;
+
+ len = (int) strlen(s);
+ while (stable->nextFree + len + 1 >= stable->size) {
+ assert(stable->size < 1000000);
+ str = (char *) malloc(stable->size*2);
+ memcpy(str, stable->strings, stable->size);
+ free(stable->strings);
+ stable->strings = str;
+ stable->size = stable->size*2;
+ }
+ loc = stable->nextFree;
+ strcpy(&stable->strings[loc], s);
+ stable->nextFree += len + 1;
+ return loc;
+} // AddString
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////// Hash table: ///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#define INIT_HASH_TABLE_SIZE 2047
+#define HASH_TABLE_MAX_COLLISIONS 3
+
+typedef struct HashEntry_Rec {
+ int index; // String table offset of string representation
+ int value; // Atom (symbol) value
+} HashEntry;
+
+typedef struct HashTable_Rec {
+ HashEntry *entry;
+ int size;
+ int entries;
+ int counts[HASH_TABLE_MAX_COLLISIONS + 1];
+} HashTable;
+
+/*
+ * InitHashTable() - Initialize the hash table.
+ *
+ */
+
+static int InitHashTable(HashTable *htable, int fsize)
+{
+ int ii;
+
+ htable->entry = (HashEntry *) malloc(sizeof(HashEntry)*fsize);
+ if (!htable->entry)
+ return 0;
+ htable->size = fsize;
+ for (ii = 0; ii < fsize; ii++) {
+ htable->entry[ii].index = 0;
+ htable->entry[ii].value = 0;
+ }
+ htable->entries = 0;
+ for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++)
+ htable->counts[ii] = 0;
+ return 1;
+} // InitHashTable
+
+/*
+ * FreeHashTable() - Free the hash table.
+ *
+ */
+
+static void FreeHashTable(HashTable *htable)
+{
+ if (htable->entry)
+ free(htable->entry);
+ htable->entry = NULL;
+ htable->size = 0;
+ htable->entries = 0;
+} // FreeHashTable
+
+/*
+ * Empty() - See if a hash table entry is empty.
+ *
+ */
+
+static int Empty(HashTable *htable, int hashloc)
+{
+ assert(hashloc >= 0 && hashloc < htable->size);
+ if (htable->entry[hashloc].index == 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+} // Empty
+
+/*
+ * Match() - See if a hash table entry is matches a string.
+ *
+ */
+
+static int Match(HashTable *htable, StringTable *stable, const char *s, int hashloc)
+{
+ int strloc;
+
+ strloc = htable->entry[hashloc].index;
+ if (!strcmp(s, &stable->strings[strloc])) {
+ return 1;
+ } else {
+ return 0;
+ }
+} // Match
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////// Atom table: ///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#define INIT_ATOM_TABLE_SIZE 1024
+
+
+struct AtomTable_Rec {
+ StringTable stable; // String table.
+ HashTable htable; // Hashes string to atom number and token value. Multiple strings can
+ // have the same token value but each unique string is a unique atom.
+ int *amap; // Maps atom value to offset in string table. Atoms all map to unique
+ // strings except for some undefined values in the lower, fixed part
+ // of the atom table that map to "<undefined>". The lowest 256 atoms
+ // correspond to single character ASCII values except for alphanumeric
+ // characters and '_', which can be other tokens. Next come the
+ // language tokens with their atom values equal to the token value.
+ // Then come predefined atoms, followed by user specified identifiers.
+ int *arev; // Reversed atom for symbol table use.
+ int nextFree;
+ int size;
+};
+
+static AtomTable latable = { { 0 } };
+AtomTable *atable = &latable;
+
+static int AddAtomFixed(AtomTable *atable, const char *s, int atom);
+
+/*
+ * GrowAtomTable() - Grow the atom table to at least "size" if it's smaller.
+ *
+ */
+
+static int GrowAtomTable(AtomTable *atable, int size)
+{
+ int *newmap, *newrev;
+
+ if (atable->size < size) {
+ if (atable->amap) {
+ newmap = realloc(atable->amap, sizeof(int)*size);
+ newrev = realloc(atable->arev, sizeof(int)*size);
+ } else {
+ newmap = malloc(sizeof(int)*size);
+ newrev = malloc(sizeof(int)*size);
+ atable->size = 0;
+ }
+ if (!newmap || !newrev) {
+ /* failed to grow -- error */
+ if (newmap)
+ atable->amap = newmap;
+ if (newrev)
+ atable->amap = newrev;
+ return -1;
+ }
+ memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int));
+ memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int));
+ atable->amap = newmap;
+ atable->arev = newrev;
+ atable->size = size;
+ }
+ return 0;
+} // GrowAtomTable
+
+/*
+ * lReverse() - Reverse the bottom 20 bits of a 32 bit int.
+ *
+ */
+
+static int lReverse(int fval)
+{
+ unsigned int in = fval;
+ int result = 0, cnt = 0;
+
+ while(in) {
+ result <<= 1;
+ result |= in&1;
+ in >>= 1;
+ cnt++;
+ }
+
+ // Don't use all 31 bits. One million atoms is plenty and sometimes the
+ // upper bits are used for other things.
+
+ if (cnt < 20)
+ result <<= 20 - cnt;
+ return result;
+} // lReverse
+
+/*
+ * AllocateAtom() - Allocate a new atom. Associated with the "undefined" value of -1.
+ *
+ */
+
+static int AllocateAtom(AtomTable *atable)
+{
+ if (atable->nextFree >= atable->size)
+ GrowAtomTable(atable, atable->nextFree*2);
+ atable->amap[atable->nextFree] = -1;
+ atable->arev[atable->nextFree] = lReverse(atable->nextFree);
+ atable->nextFree++;
+ return atable->nextFree - 1;
+} // AllocateAtom
+
+/*
+ * SetAtomValue() - Allocate a new atom associated with "hashindex".
+ *
+ */
+
+static void SetAtomValue(AtomTable *atable, int atomnumber, int hashindex)
+{
+ atable->amap[atomnumber] = atable->htable.entry[hashindex].index;
+ atable->htable.entry[hashindex].value = atomnumber;
+} // SetAtomValue
+
+/*
+ * FindHashLoc() - Find the hash location for this string. Return -1 it hash table is full.
+ *
+ */
+
+static int FindHashLoc(AtomTable *atable, const char *s)
+{
+ int hashloc, hashdelta, count;
+ int FoundEmptySlot = 0;
+ int collision[HASH_TABLE_MAX_COLLISIONS + 1];
+
+ hashloc = HashString(s) % atable->htable.size;
+ if (!Empty(&atable->htable, hashloc)) {
+ if (Match(&atable->htable, &atable->stable, s, hashloc))
+ return hashloc;
+ collision[0] = hashloc;
+ hashdelta = HashString2(s);
+ count = 0;
+ while (count < HASH_TABLE_MAX_COLLISIONS) {
+ hashloc = ((hashloc + hashdelta) & 0x7fffffff) % atable->htable.size;
+ if (!Empty(&atable->htable, hashloc)) {
+ if (Match(&atable->htable, &atable->stable, s, hashloc)) {
+ return hashloc;
+ }
+ } else {
+ FoundEmptySlot = 1;
+ break;
+ }
+ count++;
+ collision[count] = hashloc;
+ }
+
+ if (!FoundEmptySlot) {
+ if (cpp->options.DumpAtomTable) {
+ int ii;
+ char str[200];
+ sprintf(str, "*** Hash failed with more than %d collisions. Must increase hash table size. ***",
+ HASH_TABLE_MAX_COLLISIONS);
+ CPPShInfoLogMsg(str);
+
+ sprintf(str, "*** New string \"%s\", hash=%04x, delta=%04x", s, collision[0], hashdelta);
+ CPPShInfoLogMsg(str);
+ for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) {
+ sprintf(str, "*** Collides on try %d at hash entry %04x with \"%s\"",
+ ii + 1, collision[ii], GetAtomString(atable, atable->htable.entry[collision[ii]].value));
+ CPPShInfoLogMsg(str);
+ }
+ }
+ return -1;
+ } else {
+ atable->htable.counts[count]++;
+ }
+ }
+ return hashloc;
+} // FindHashLoc
+
+/*
+ * IncreaseHashTableSize()
+ *
+ */
+
+static int IncreaseHashTableSize(AtomTable *atable)
+{
+ int ii, strloc, oldhashloc, value, size;
+ AtomTable oldtable;
+ char *s;
+
+ // Save the old atom table and create a new one:
+
+ oldtable = *atable;
+ size = oldtable.htable.size*2 + 1;
+ if (!InitAtomTable(atable, size))
+ return 0;
+
+ // Add all the existing values to the new atom table preserving their atom values:
+
+ for (ii = atable->nextFree; ii < oldtable.nextFree; ii++) {
+ strloc = oldtable.amap[ii];
+ s = &oldtable.stable.strings[strloc];
+ oldhashloc = FindHashLoc(&oldtable, s);
+ assert(oldhashloc >= 0);
+ value = oldtable.htable.entry[oldhashloc].value;
+ AddAtomFixed(atable, s, value);
+ }
+ FreeAtomTable(&oldtable);
+ return 1;
+} // IncreaseHashTableSize
+
+/*
+ * LookUpAddStringHash() - Lookup a string in the hash table. If it's not there, add it and
+ * initialize the atom value in the hash table to 0. Return the hash table index.
+ */
+
+static int LookUpAddStringHash(AtomTable *atable, const char *s)
+{
+ int hashloc, strloc;
+
+ while(1) {
+ hashloc = FindHashLoc(atable, s);
+ if (hashloc >= 0)
+ break;
+ IncreaseHashTableSize(atable);
+ }
+
+ if (Empty(&atable->htable, hashloc)) {
+ atable->htable.entries++;
+ strloc = AddString(&atable->stable, s);
+ atable->htable.entry[hashloc].index = strloc;
+ atable->htable.entry[hashloc].value = 0;
+ }
+ return hashloc;
+} // LookUpAddStringHash
+
+/*
+ * LookUpAddString() - Lookup a string in the hash table. If it's not there, add it and
+ * initialize the atom value in the hash table to the next atom number.
+ * Return the atom value of string.
+ */
+
+int LookUpAddString(AtomTable *atable, const char *s)
+{
+ int hashindex, atom;
+
+ hashindex = LookUpAddStringHash(atable, s);
+ atom = atable->htable.entry[hashindex].value;
+ if (atom == 0) {
+ atom = AllocateAtom(atable);
+ SetAtomValue(atable, atom, hashindex);
+ }
+ return atom;
+} // LookUpAddString
+
+/*
+ * GetAtomString()
+ *
+ */
+
+const char *GetAtomString(AtomTable *atable, int atom)
+{
+ int soffset;
+
+ if (atom > 0 && atom < atable->nextFree) {
+ soffset = atable->amap[atom];
+ if (soffset > 0 && soffset < atable->stable.nextFree) {
+ return &atable->stable.strings[soffset];
+ } else {
+ return "<internal error: bad soffset>";
+ }
+ } else {
+ if (atom == 0) {
+ return "<null atom>";
+ } else {
+ if (atom == EOF) {
+ return "<EOF>";
+ } else {
+ return "<invalid atom>";
+ }
+ }
+ }
+} // GetAtomString
+
+/*
+ * GetReversedAtom()
+ *
+ */
+
+int GetReversedAtom(AtomTable *atable, int atom)
+{
+ if (atom > 0 && atom < atable->nextFree) {
+ return atable->arev[atom];
+ } else {
+ return 0;
+ }
+} // GetReversedAtom
+
+/*
+ * AddAtom() - Add a string to the atom, hash and string tables if it isn't already there.
+ * Return it's atom index.
+ */
+
+int AddAtom(AtomTable *atable, const char *s)
+{
+ int atom;
+
+ atom = LookUpAddString(atable, s);
+ return atom;
+} // AddAtom
+
+/*
+ * AddAtomFixed() - Add an atom to the hash and string tables if it isn't already there.
+ * Assign it the atom value of "atom".
+ */
+
+static int AddAtomFixed(AtomTable *atable, const char *s, int atom)
+{
+ int hashindex, lsize;
+
+ hashindex = LookUpAddStringHash(atable, s);
+ if (atable->nextFree >= atable->size || atom >= atable->size) {
+ lsize = atable->size*2;
+ if (lsize <= atom)
+ lsize = atom + 1;
+ GrowAtomTable(atable, lsize);
+ }
+ atable->amap[atom] = atable->htable.entry[hashindex].index;
+ atable->htable.entry[hashindex].value = atom;
+ //if (atom >= atable->nextFree)
+ // atable->nextFree = atom + 1;
+ while (atom >= atable->nextFree) {
+ atable->arev[atable->nextFree] = lReverse(atable->nextFree);
+ atable->nextFree++;
+ }
+ return atom;
+} // AddAtomFixed
+
+/*
+ * InitAtomTable() - Initialize the atom table.
+ *
+ */
+
+int InitAtomTable(AtomTable *atable, int htsize)
+{
+ unsigned int ii;
+
+ htsize = htsize <= 0 ? INIT_HASH_TABLE_SIZE : htsize;
+ if (!InitStringTable(&atable->stable))
+ return 0;
+ if (!InitHashTable(&atable->htable, htsize))
+ return 0;
+
+ atable->nextFree = 0;
+ atable->amap = NULL;
+ atable->size = 0;
+ GrowAtomTable(atable, INIT_ATOM_TABLE_SIZE);
+ if (!atable->amap)
+ return 0;
+
+ // Initialize lower part of atom table to "<undefined>" atom:
+
+ AddAtomFixed(atable, "<undefined>", 0);
+ for (ii = 0; ii < FIRST_USER_TOKEN_SY; ii++)
+ atable->amap[ii] = atable->amap[0];
+
+ // Add single character tokens to the atom table:
+
+ {
+ const char *s = "~!%^&*()-+=|,.<>/?;:[]{}#";
+ char t[2];
+
+ t[1] = '\0';
+ while (*s) {
+ t[0] = *s;
+ AddAtomFixed(atable, t, s[0]);
+ s++;
+ }
+ }
+
+ // Add multiple character scanner tokens :
+
+ for (ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++)
+ AddAtomFixed(atable, tokens[ii].str, tokens[ii].val);
+
+ // Add error symbol if running in error mode:
+
+ if (cpp->options.ErrorMode)
+ AddAtomFixed(atable, "error", ERROR_SY);
+
+ AddAtom(atable, "<*** end fixed atoms ***>");
+
+ return 1;
+} // InitAtomTable
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////// Debug Printing Functions: //////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * PrintAtomTable()
+ *
+ */
+
+void PrintAtomTable(AtomTable *atable)
+{
+ int ii;
+ char str[200];
+
+ for (ii = 0; ii < atable->nextFree; ii++) {
+ sprintf(str, "%d: \"%s\"", ii, &atable->stable.strings[atable->amap[ii]]);
+ CPPDebugLogMsg(str);
+ }
+ sprintf(str, "Hash table: size=%d, entries=%d, collisions=",
+ atable->htable.size, atable->htable.entries);
+ CPPDebugLogMsg(str);
+ for (ii = 0; ii < HASH_TABLE_MAX_COLLISIONS; ii++) {
+ sprintf(str, " %d", atable->htable.counts[ii]);
+ CPPDebugLogMsg(str);
+ }
+
+} // PrintAtomTable
+
+
+/*
+ * GetStringOfAtom()
+ *
+ */
+
+char* GetStringOfAtom(AtomTable *atable, int atom)
+{
+ char* chr_str;
+ chr_str=&atable->stable.strings[atable->amap[atom]];
+ return chr_str;
+} // GetStringOfAtom
+
+/*
+ * FreeAtomTable() - Free the atom table and associated memory
+ *
+ */
+
+void FreeAtomTable(AtomTable *atable)
+{
+ FreeStringTable(&atable->stable);
+ FreeHashTable(&atable->htable);
+ if (atable->amap)
+ free(atable->amap);
+ if (atable->arev)
+ free(atable->arev);
+ atable->amap = NULL;
+ atable->arev = NULL;
+ atable->nextFree = 0;
+ atable->size = 0;
+} // FreeAtomTable
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////// End of atom.c ///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/atom.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/atom.h
new file mode 100644
index 000000000..1d84c3251
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/atom.h
@@ -0,0 +1,63 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// atom.h
+//
+
+#if !defined(__ATOM_H)
+#define __ATOM_H 1
+
+typedef struct AtomTable_Rec AtomTable;
+
+extern AtomTable *atable;
+
+int InitAtomTable(AtomTable *atable, int htsize);
+void FreeAtomTable(AtomTable *atable);
+int AddAtom(AtomTable *atable, const char *s);
+void PrintAtomTable(AtomTable *atable);
+int LookUpAddString(AtomTable *atable, const char *s);
+const char *GetAtomString(AtomTable *atable, int atom);
+int GetReversedAtom(AtomTable *atable, int atom);
+char* GetStringOfAtom(AtomTable *atable, int atom);
+#endif // !defined(__ATOM_H)
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/compile.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/compile.h
new file mode 100644
index 000000000..11808531c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/compile.h
@@ -0,0 +1,100 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// compile.h
+//
+
+#if !defined(__COMPILE_H)
+#define __COMPILE_H 1
+
+int InitCPPStruct(void);
+
+typedef struct Options_Rec{
+ const char *profileString;
+ int ErrorMode;
+ int Quiet;
+
+ // Debug The Compiler options:
+ int DumpAtomTable;
+} Options;
+
+#define MAX_IF_NESTING 64
+struct CPPStruct_Rec {
+ // Public members
+ SourceLoc *pLastSourceLoc; // Set at the start of each statement by the tree walkers
+ Options options; // Compile options and parameters
+
+ // Private members
+ SourceLoc lastSourceLoc;
+
+ // Scanner data:
+
+ SourceLoc *tokenLoc; // Source location of most recent token seen by the scanner
+ int mostRecentToken; // Most recent token seen by the scanner
+ InputSrc *currentInput;
+ int previous_token;
+ int pastFirstStatement; // used to make sure that #version is the first statement seen in the file, if present
+
+ void *pC; // storing the parseContext of the compile object in cpp.
+
+ // Private members:
+ SourceLoc ltokenLoc;
+ int ifdepth; //current #if-#else-#endif nesting in the cpp.c file (pre-processor)
+ int elsedepth[MAX_IF_NESTING];//Keep a track of #if depth..Max allowed is 64.
+ int elsetracker; //#if-#else and #endif constructs...Counter.
+ const char *ErrMsg;
+ int CompileError; //Indicate compile error when #error, #else,#elif mismatch.
+
+ //
+ // Globals used to communicate between PaParseStrings() and yy_input()and
+ // also across the files.(gen_glslang.cpp and scanner.c)
+ //
+ int PaWhichStr; // which string we're parsing
+ const int* PaStrLen; // array of lengths of the PaArgv strings
+ int PaArgc; // count of strings in the array
+ const char* const* PaArgv; // our array of strings to parse
+ unsigned int tokensBeforeEOF : 1;
+};
+
+#endif // !defined(__COMPILE_H)
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cpp.c b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cpp.c
new file mode 100644
index 000000000..03dd4f674
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cpp.c
@@ -0,0 +1,1114 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// cpp.c
+//
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "compiler/preprocessor/slglobals.h"
+
+static int CPPif(yystypepp * yylvalpp);
+
+/* Don't use memory.c's replacements, as we clean up properly here */
+#undef malloc
+#undef free
+
+static int bindAtom = 0;
+static int constAtom = 0;
+static int defaultAtom = 0;
+static int defineAtom = 0;
+static int definedAtom = 0;
+static int elseAtom = 0;
+static int elifAtom = 0;
+static int endifAtom = 0;
+static int ifAtom = 0;
+static int ifdefAtom = 0;
+static int ifndefAtom = 0;
+static int includeAtom = 0;
+static int lineAtom = 0;
+static int pragmaAtom = 0;
+static int texunitAtom = 0;
+static int undefAtom = 0;
+static int errorAtom = 0;
+static int __LINE__Atom = 0;
+static int __FILE__Atom = 0;
+static int __VERSION__Atom = 0;
+static int versionAtom = 0;
+static int extensionAtom = 0;
+
+static Scope *macros = 0;
+#define MAX_MACRO_ARGS 64
+
+static SourceLoc ifloc; /* outermost #if */
+
+int InitCPP(void)
+{
+ char buffer[64], *t;
+ const char *f;
+
+ // Add various atoms needed by the CPP line scanner:
+ bindAtom = LookUpAddString(atable, "bind");
+ constAtom = LookUpAddString(atable, "const");
+ defaultAtom = LookUpAddString(atable, "default");
+ defineAtom = LookUpAddString(atable, "define");
+ definedAtom = LookUpAddString(atable, "defined");
+ elifAtom = LookUpAddString(atable, "elif");
+ elseAtom = LookUpAddString(atable, "else");
+ endifAtom = LookUpAddString(atable, "endif");
+ ifAtom = LookUpAddString(atable, "if");
+ ifdefAtom = LookUpAddString(atable, "ifdef");
+ ifndefAtom = LookUpAddString(atable, "ifndef");
+ includeAtom = LookUpAddString(atable, "include");
+ lineAtom = LookUpAddString(atable, "line");
+ pragmaAtom = LookUpAddString(atable, "pragma");
+ texunitAtom = LookUpAddString(atable, "texunit");
+ undefAtom = LookUpAddString(atable, "undef");
+ errorAtom = LookUpAddString(atable, "error");
+ __LINE__Atom = LookUpAddString(atable, "__LINE__");
+ __FILE__Atom = LookUpAddString(atable, "__FILE__");
+ __VERSION__Atom = LookUpAddString(atable, "__VERSION__");
+ versionAtom = LookUpAddString(atable, "version");
+ extensionAtom = LookUpAddString(atable, "extension");
+ macros = NewScopeInPool(mem_CreatePool(0, 0));
+ strcpy(buffer, "PROFILE_");
+ t = buffer + strlen(buffer);
+ f = cpp->options.profileString;
+ while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1)
+ *t++ = toupper(*f++);
+ *t = 0;
+
+ PredefineIntMacro("GL_ES", 1);
+ PredefineIntMacro("GL_FRAGMENT_PRECISION_HIGH", 1);
+
+ return 1;
+} // InitCPP
+
+int FreeCPP(void)
+{
+ if (macros)
+ {
+ mem_FreePool(macros->pool);
+ macros = 0;
+ }
+
+ return 1;
+}
+
+int FinalCPP(void)
+{
+ if (cpp->ifdepth)
+ CPPErrorToInfoLog("#if mismatch");
+ return 1;
+}
+
+static int CPPdefine(yystypepp * yylvalpp)
+{
+ int token, name, args[MAX_MACRO_ARGS], argc;
+ const char *message;
+ MacroSymbol mac;
+ Symbol *symb;
+ SourceLoc dummyLoc;
+ memset(&mac, 0, sizeof(mac));
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != CPP_IDENTIFIER) {
+ CPPErrorToInfoLog("#define");
+ return token;
+ }
+ name = yylvalpp->sc_ident;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token == '(' && !yylvalpp->sc_int) {
+ // gather arguments
+ argc = 0;
+ do {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (argc == 0 && token == ')') break;
+ if (token != CPP_IDENTIFIER) {
+ CPPErrorToInfoLog("#define");
+ return token;
+ }
+ if (argc < MAX_MACRO_ARGS)
+ args[argc++] = yylvalpp->sc_ident;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ } while (token == ',');
+ if (token != ')') {
+ CPPErrorToInfoLog("#define");
+ return token;
+ }
+ mac.argc = argc;
+ mac.args = mem_Alloc(macros->pool, argc * sizeof(int));
+ memcpy(mac.args, args, argc * sizeof(int));
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool);
+ while (token != '\n') {
+ if (token == '\\') {
+ CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
+ return token;
+ } else if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #define preprocessor directive - expected a newline");
+ return 0;
+ }
+ RecordToken(mac.body, token, yylvalpp);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ };
+
+ symb = LookUpSymbol(macros, name);
+ if (symb) {
+ if (!symb->details.mac.undef) {
+ // already defined -- need to make sure they are identical
+ if (symb->details.mac.argc != mac.argc) goto error;
+ for (argc=0; argc < mac.argc; argc++)
+ if (symb->details.mac.args[argc] != mac.args[argc])
+ goto error;
+ RewindTokenStream(symb->details.mac.body);
+ RewindTokenStream(mac.body);
+ do {
+ int old_lval, old_token;
+ old_token = ReadToken(symb->details.mac.body, yylvalpp);
+ old_lval = yylvalpp->sc_int;
+ token = ReadToken(mac.body, yylvalpp);
+ if (token != old_token || yylvalpp->sc_int != old_lval) {
+ error:
+ StoreStr("Macro Redefined");
+ StoreStr(GetStringOfAtom(atable,name));
+ message=GetStrfromTStr();
+ DecLineNumber();
+ CPPShInfoLogMsg(message);
+ IncLineNumber();
+ ResetTString();
+ break; }
+ } while (token > 0);
+ }
+ //FreeMacro(&symb->details.mac);
+ } else {
+ dummyLoc.file = 0;
+ dummyLoc.line = 0;
+ symb = AddSymbol(&dummyLoc, macros, name, MACRO_S);
+ }
+ symb->details.mac = mac;
+ return '\n';
+} // CPPdefine
+
+static int CPPundef(yystypepp * yylvalpp)
+{
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ Symbol *symb;
+ if(token == '\n'){
+ CPPErrorToInfoLog("#undef");
+ return token;
+ }
+ if (token != CPP_IDENTIFIER)
+ goto error;
+ symb = LookUpSymbol(macros, yylvalpp->sc_ident);
+ if (symb) {
+ symb->details.mac.undef = 1;
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '\n') {
+ error:
+ CPPErrorToInfoLog("#undef");
+ }
+ return token;
+} // CPPundef
+
+/* CPPelse -- skip forward to appropriate spot. This is actually used
+** to skip to and #endif after seeing an #else, AND to skip to a #else,
+** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false
+*/
+
+static int CPPelse(int matchelse, yystypepp * yylvalpp)
+{
+ int atom,depth=0;
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ while (token > 0) {
+ if (token != '#') {
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #else preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ continue;
+ }
+ if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER)
+ continue;
+ atom = yylvalpp->sc_ident;
+ if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){
+ depth++; cpp->ifdepth++; cpp->elsetracker++;
+ if (cpp->ifdepth > MAX_IF_NESTING) {
+ CPPErrorToInfoLog("max #if nesting depth exceeded");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ // sanity check elsetracker
+ if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
+ CPPErrorToInfoLog("mismatched #if/#endif statements");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsedepth[cpp->elsetracker] = 0;
+ }
+ else if (atom == endifAtom) {
+ if(--depth<0){
+ if (cpp->elsetracker)
+ --cpp->elsetracker;
+ if (cpp->ifdepth)
+ --cpp->ifdepth;
+ break;
+ }
+ --cpp->elsetracker;
+ --cpp->ifdepth;
+ }
+ else if (((int)(matchelse) != 0)&& depth==0) {
+ if (atom == elseAtom ) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '\n') {
+ CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input following #else preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ }
+ break;
+ }
+ else if (atom == elifAtom) {
+ /* we decrement cpp->ifdepth here, because CPPif will increment
+ * it and we really want to leave it alone */
+ if (cpp->ifdepth){
+ --cpp->ifdepth;
+ --cpp->elsetracker;
+ }
+ return CPPif(yylvalpp);
+ }
+ }
+ else if((atom==elseAtom) && (!ChkCorrectElseNesting())){
+ CPPErrorToInfoLog("#else after a #else");
+ cpp->CompileError=1;
+ return 0;
+ }
+ };
+ return token;
+}
+
+enum eval_prec {
+ MIN_PREC,
+ COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY,
+ MAX_PREC
+};
+
+static int op_logor(int a, int b) { return a || b; }
+static int op_logand(int a, int b) { return a && b; }
+static int op_or(int a, int b) { return a | b; }
+static int op_xor(int a, int b) { return a ^ b; }
+static int op_and(int a, int b) { return a & b; }
+static int op_eq(int a, int b) { return a == b; }
+static int op_ne(int a, int b) { return a != b; }
+static int op_ge(int a, int b) { return a >= b; }
+static int op_le(int a, int b) { return a <= b; }
+static int op_gt(int a, int b) { return a > b; }
+static int op_lt(int a, int b) { return a < b; }
+static int op_shl(int a, int b) { return a << b; }
+static int op_shr(int a, int b) { return a >> b; }
+static int op_add(int a, int b) { return a + b; }
+static int op_sub(int a, int b) { return a - b; }
+static int op_mul(int a, int b) { return a * b; }
+static int op_div(int a, int b) { return a / b; }
+static int op_mod(int a, int b) { return a % b; }
+static int op_pos(int a) { return a; }
+static int op_neg(int a) { return -a; }
+static int op_cmpl(int a) { return ~a; }
+static int op_not(int a) { return !a; }
+
+struct {
+ int token, prec, (*op)(int, int);
+} binop[] = {
+ { CPP_OR_OP, LOGOR, op_logor },
+ { CPP_AND_OP, LOGAND, op_logand },
+ { '|', OR, op_or },
+ { '^', XOR, op_xor },
+ { '&', AND, op_and },
+ { CPP_EQ_OP, EQUAL, op_eq },
+ { CPP_NE_OP, EQUAL, op_ne },
+ { '>', RELATION, op_gt },
+ { CPP_GE_OP, RELATION, op_ge },
+ { '<', RELATION, op_lt },
+ { CPP_LE_OP, RELATION, op_le },
+ { CPP_LEFT_OP, SHIFT, op_shl },
+ { CPP_RIGHT_OP, SHIFT, op_shr },
+ { '+', ADD, op_add },
+ { '-', ADD, op_sub },
+ { '*', MUL, op_mul },
+ { '/', MUL, op_div },
+ { '%', MUL, op_mod },
+};
+
+struct {
+ int token, (*op)(int);
+} unop[] = {
+ { '+', op_pos },
+ { '-', op_neg },
+ { '~', op_cmpl },
+ { '!', op_not },
+};
+
+#define ALEN(A) (sizeof(A)/sizeof(A[0]))
+
+static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp)
+{
+ int i, val;
+ Symbol *s;
+ if (token == CPP_IDENTIFIER) {
+ if (yylvalpp->sc_ident == definedAtom) {
+ int needclose = 0;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token == '(') {
+ needclose = 1;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ if (token != CPP_IDENTIFIER)
+ goto error;
+ *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident))
+ ? !s->details.mac.undef : 0;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (needclose) {
+ if (token != ')')
+ goto error;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ return eval(token, prec, res, err, yylvalpp);
+ } else {
+ goto error;
+ }
+ } else if (token == CPP_INTCONSTANT) {
+ *res = yylvalpp->sc_int;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ } else if (token == '(') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ token = eval(token, MIN_PREC, res, err, yylvalpp);
+ if (!*err) {
+ if (token != ')')
+ goto error;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ } else {
+ for (i = ALEN(unop) - 1; i >= 0; i--) {
+ if (unop[i].token == token)
+ break;
+ }
+ if (i >= 0) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ token = eval(token, UNARY, res, err, yylvalpp);
+ *res = unop[i].op(*res);
+ } else {
+ goto error;
+ }
+ }
+ while (!*err) {
+ if (token == ')' || token == '\n') break;
+ for (i = ALEN(binop) - 1; i >= 0; i--) {
+ if (binop[i].token == token)
+ break;
+ }
+ if (i < 0 || binop[i].prec <= prec)
+ break;
+ val = *res;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ token = eval(token, binop[i].prec, res, err, yylvalpp);
+
+ if (binop[i].op == op_div || binop[i].op == op_mod)
+ {
+ if (*res == 0)
+ {
+ CPPErrorToInfoLog("preprocessor divide or modulo by zero");
+ *err = 1;
+ return token;
+ }
+ }
+
+ *res = binop[i].op(val, *res);
+ }
+ return token;
+error:
+ CPPErrorToInfoLog("incorrect preprocessor directive");
+ *err = 1;
+ *res = 0;
+ return token;
+} // eval
+
+static int CPPif(yystypepp * yylvalpp) {
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ int res = 0, err = 0;
+
+ if (!cpp->ifdepth++)
+ ifloc = *cpp->tokenLoc;
+ if(cpp->ifdepth > MAX_IF_NESTING){
+ CPPErrorToInfoLog("max #if nesting depth exceeded");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsetracker++;
+ // sanity check elsetracker
+ if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
+ CPPErrorToInfoLog("mismatched #if/#endif statements");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsedepth[cpp->elsetracker] = 0;
+
+ token = eval(token, MIN_PREC, &res, &err, yylvalpp);
+ if (token != '\n') {
+ CPPWarningToInfoLog("unexpected tokens following #if preprocessor directive - expected a newline");
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #if preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ }
+ if (!res && !err) {
+ token = CPPelse(1, yylvalpp);
+ }
+
+ return token;
+} // CPPif
+
+static int CPPifdef(int defined, yystypepp * yylvalpp)
+{
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ int name = yylvalpp->sc_ident;
+ if(++cpp->ifdepth > MAX_IF_NESTING){
+ CPPErrorToInfoLog("max #if nesting depth exceeded");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsetracker++;
+ // sanity check elsetracker
+ if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
+ CPPErrorToInfoLog("mismatched #if/#endif statements");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ cpp->elsedepth[cpp->elsetracker] = 0;
+
+ if (token != CPP_IDENTIFIER) {
+ defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef");
+ } else {
+ Symbol *s = LookUpSymbol(macros, name);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '\n') {
+ CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline");
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #ifdef preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ }
+ if (((s && !s->details.mac.undef) ? 1 : 0) != defined)
+ token = CPPelse(1, yylvalpp);
+ }
+ return token;
+} // CPPifdef
+
+static int CPPline(yystypepp * yylvalpp)
+{
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if(token=='\n'){
+ DecLineNumber();
+ CPPErrorToInfoLog("#line");
+ IncLineNumber();
+ return token;
+ }
+ else if (token == CPP_INTCONSTANT) {
+ yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
+ SetLineNumber(yylvalpp->sc_int);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ if (token == CPP_INTCONSTANT) {
+ yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
+ SetStringNumber(yylvalpp->sc_int);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if(token!='\n')
+ CPPErrorToInfoLog("#line");
+ }
+ else if (token == '\n'){
+ return token;
+ }
+ else{
+ CPPErrorToInfoLog("#line");
+ }
+ }
+ else{
+ CPPErrorToInfoLog("#line");
+ }
+ return token;
+}
+
+static int CPPerror(yystypepp * yylvalpp) {
+
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ const char *message;
+
+ while (token != '\n') {
+ if (token <= 0){
+ CPPErrorToInfoLog("unexpected end of input in #error preprocessor directive - expected a newline");
+ return 0;
+ }else if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
+ StoreStr(yylvalpp->symbol_name);
+ }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){
+ StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
+ }else {
+ StoreStr(GetStringOfAtom(atable,token));
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ DecLineNumber();
+ //store this msg into the shader's information log..set the Compile Error flag!!!!
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ cpp->CompileError=1;
+ IncLineNumber();
+ return '\n';
+}//CPPerror
+
+static int CPPpragma(yystypepp * yylvalpp)
+{
+ char SrcStrName[2];
+ char** allTokens;
+ int tokenCount = 0;
+ int maxTokenCount = 10;
+ const char* SrcStr;
+ int i;
+
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ if (token=='\n') {
+ DecLineNumber();
+ CPPErrorToInfoLog("#pragma");
+ IncLineNumber();
+ return token;
+ }
+
+ allTokens = (char**)malloc(sizeof(char*) * maxTokenCount);
+
+ while (token != '\n') {
+ if (tokenCount >= maxTokenCount) {
+ maxTokenCount *= 2;
+ allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount);
+ }
+ switch (token) {
+ case CPP_IDENTIFIER:
+ SrcStr = GetAtomString(atable, yylvalpp->sc_ident);
+ allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
+ strcpy(allTokens[tokenCount++], SrcStr);
+ break;
+ case CPP_INTCONSTANT:
+ SrcStr = yylvalpp->symbol_name;
+ allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
+ strcpy(allTokens[tokenCount++], SrcStr);
+ break;
+ case CPP_FLOATCONSTANT:
+ SrcStr = yylvalpp->symbol_name;
+ allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1);
+ strcpy(allTokens[tokenCount++], SrcStr);
+ break;
+ case -1:
+ // EOF
+ CPPShInfoLogMsg("#pragma directive must end with a newline");
+ return token;
+ default:
+ SrcStrName[0] = token;
+ SrcStrName[1] = '\0';
+ allTokens[tokenCount] = (char*)malloc(2);
+ strcpy(allTokens[tokenCount++], SrcStrName);
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+
+ cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp);
+ HandlePragma((const char**)allTokens, tokenCount);
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ for (i = 0; i < tokenCount; ++i) {
+ free (allTokens[i]);
+ }
+ free (allTokens);
+
+ return token;
+} // CPPpragma
+
+#define ESSL_VERSION_NUMBER 100
+#define ESSL_VERSION_STRING "100"
+
+static int CPPversion(yystypepp * yylvalpp)
+{
+
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ if (cpp->pastFirstStatement == 1)
+ CPPShInfoLogMsg("#version must occur before any other statement in the program");
+
+ if(token=='\n'){
+ DecLineNumber();
+ CPPErrorToInfoLog("#version");
+ IncLineNumber();
+ return token;
+ }
+ if (token != CPP_INTCONSTANT)
+ CPPErrorToInfoLog("#version");
+
+ yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
+ //SetVersionNumber(yylvalpp->sc_int);
+
+ if (yylvalpp->sc_int != ESSL_VERSION_NUMBER)
+ CPPShInfoLogMsg("Version number not supported by ESSL");
+
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+
+ if (token == '\n'){
+ return token;
+ }
+ else{
+ CPPErrorToInfoLog("#version");
+ }
+ return token;
+} // CPPversion
+
+static int CPPextension(yystypepp * yylvalpp)
+{
+
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ char extensionName[MAX_SYMBOL_NAME_LEN + 1];
+
+ if(token=='\n'){
+ DecLineNumber();
+ CPPShInfoLogMsg("extension name not specified");
+ IncLineNumber();
+ return token;
+ }
+
+ if (token != CPP_IDENTIFIER)
+ CPPErrorToInfoLog("#extension");
+
+ strncpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident), MAX_SYMBOL_NAME_LEN);
+ extensionName[MAX_SYMBOL_NAME_LEN] = '\0';
+
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != ':') {
+ CPPShInfoLogMsg("':' missing after extension name");
+ return token;
+ }
+
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != CPP_IDENTIFIER) {
+ CPPShInfoLogMsg("behavior for extension not specified");
+ return token;
+ }
+
+ updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident));
+
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token == '\n'){
+ return token;
+ }
+ else{
+ CPPErrorToInfoLog("#extension");
+ }
+ return token;
+} // CPPextension
+
+int readCPPline(yystypepp * yylvalpp)
+{
+ int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ const char *message;
+ int isVersion = 0;
+
+ if (token == CPP_IDENTIFIER) {
+ if (yylvalpp->sc_ident == defineAtom) {
+ token = CPPdefine(yylvalpp);
+ } else if (yylvalpp->sc_ident == elseAtom) {
+ if(ChkCorrectElseNesting()){
+ if (!cpp->ifdepth ){
+ CPPErrorToInfoLog("#else mismatch");
+ cpp->CompileError=1;
+ return 0;
+ }
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '\n') {
+ CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline");
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpected end of input in #ifdef preprocessor directive - expected a newline");
+ return 0;
+ }
+ }
+ }
+ token = CPPelse(0, yylvalpp);
+ }else{
+ CPPErrorToInfoLog("#else after a #else");
+ cpp->ifdepth = 0;
+ cpp->elsetracker = 0;
+ cpp->pastFirstStatement = 1;
+ cpp->CompileError = 1;
+ return 0;
+ }
+ } else if (yylvalpp->sc_ident == elifAtom) {
+ if (!cpp->ifdepth){
+ CPPErrorToInfoLog("#elif mismatch");
+ cpp->CompileError=1;
+ return 0;
+ }
+ // this token is really a dont care, but we still need to eat the tokens
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ while (token != '\n') {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) { // EOF or error
+ CPPErrorToInfoLog("unexpect tokens following #elif preprocessor directive - expected a newline");
+ cpp->CompileError = 1;
+ return 0;
+ }
+ }
+ token = CPPelse(0, yylvalpp);
+ } else if (yylvalpp->sc_ident == endifAtom) {
+ if (!cpp->ifdepth){
+ CPPErrorToInfoLog("#endif mismatch");
+ cpp->CompileError=1;
+ return 0;
+ }
+ else
+ --cpp->ifdepth;
+
+ if (cpp->elsetracker)
+ --cpp->elsetracker;
+
+ } else if (yylvalpp->sc_ident == ifAtom) {
+ token = CPPif(yylvalpp);
+ } else if (yylvalpp->sc_ident == ifdefAtom) {
+ token = CPPifdef(1, yylvalpp);
+ } else if (yylvalpp->sc_ident == ifndefAtom) {
+ token = CPPifdef(0, yylvalpp);
+ } else if (yylvalpp->sc_ident == lineAtom) {
+ token = CPPline(yylvalpp);
+ } else if (yylvalpp->sc_ident == pragmaAtom) {
+ token = CPPpragma(yylvalpp);
+ } else if (yylvalpp->sc_ident == undefAtom) {
+ token = CPPundef(yylvalpp);
+ } else if (yylvalpp->sc_ident == errorAtom) {
+ token = CPPerror(yylvalpp);
+ } else if (yylvalpp->sc_ident == versionAtom) {
+ token = CPPversion(yylvalpp);
+ isVersion = 1;
+ } else if (yylvalpp->sc_ident == extensionAtom) {
+ token = CPPextension(yylvalpp);
+ } else {
+ StoreStr("Invalid Directive");
+ StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ }
+ }
+ while (token != '\n' && token != 0 && token != EOF) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+
+ cpp->pastFirstStatement = 1;
+
+ return token;
+} // readCPPline
+
+void FreeMacro(MacroSymbol *s) {
+ DeleteTokenStream(s->body);
+}
+
+void PredefineIntMacro(const char *name, int value) {
+ SourceLoc location = {0};
+ Symbol *symbol = NULL;
+ MacroSymbol macro = {0};
+ yystypepp val = {0};
+ int atom = 0;
+
+ macro.body = NewTokenStream(name, macros->pool);
+ val.sc_int = value;
+ sprintf(val.symbol_name, "%d", value);
+ RecordToken(macro.body, CPP_INTCONSTANT, &val);
+ atom = LookUpAddString(atable, name);
+ symbol = AddSymbol(&location, macros, atom, MACRO_S);
+ symbol->details.mac = macro;
+}
+
+static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; }
+static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { }
+
+static void PushEofSrc() {
+ InputSrc *in = malloc(sizeof(InputSrc));
+ memset(in, 0, sizeof(InputSrc));
+ in->scan = eof_scan;
+ in->getch = eof_scan;
+ in->ungetch = noop;
+ in->prev = cpp->currentInput;
+ cpp->currentInput = in;
+}
+
+static void PopEofSrc() {
+ if (cpp->currentInput->scan == eof_scan) {
+ InputSrc *in = cpp->currentInput;
+ cpp->currentInput = in->prev;
+ free(in);
+ }
+}
+
+static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) {
+ int token;
+ TokenStream *n;
+ RewindTokenStream(a);
+ do {
+ token = ReadToken(a, yylvalpp);
+ if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident))
+ break;
+ } while (token > 0);
+ if (token <= 0) return a;
+ n = NewTokenStream("macro arg", 0);
+ PushEofSrc();
+ ReadFromTokenStream(a, 0, 0);
+ while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) {
+ if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp))
+ continue;
+ RecordToken(n, token, yylvalpp);
+ }
+ PopEofSrc();
+ DeleteTokenStream(a);
+ return n;
+} // PrescanMacroArg
+
+typedef struct MacroInputSrc {
+ InputSrc base;
+ MacroSymbol *mac;
+ TokenStream **args;
+} MacroInputSrc;
+
+/* macro_scan ---
+** return the next token for a macro expanion, handling macro args
+*/
+static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) {
+ int i;
+ int token = ReadToken(in->mac->body, yylvalpp);
+ if (token == CPP_IDENTIFIER) {
+ for (i = in->mac->argc-1; i>=0; i--)
+ if (in->mac->args[i] == yylvalpp->sc_ident) break;
+ if (i >= 0) {
+ ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0);
+ return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ }
+ }
+ if (token > 0) return token;
+ in->mac->busy = 0;
+ cpp->currentInput = in->base.prev;
+ if (in->args) {
+ for (i=in->mac->argc-1; i>=0; i--)
+ DeleteTokenStream(in->args[i]);
+ free(in->args);
+ }
+ free(in);
+ return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+} // macro_scan
+
+/* MacroExpand
+** check an identifier (atom) to see if it a macro that should be expanded.
+** If it is, push an InputSrc that will produce the appropriate expansion
+** and return TRUE. If not, return FALSE.
+*/
+
+int MacroExpand(int atom, yystypepp * yylvalpp)
+{
+ Symbol *sym = LookUpSymbol(macros, atom);
+ MacroInputSrc *in;
+ int i,j, token, depth=0;
+ const char *message;
+ if (atom == __LINE__Atom) {
+ yylvalpp->sc_int = GetLineNumber();
+ sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
+ UngetToken(CPP_INTCONSTANT, yylvalpp);
+ return 1;
+ }
+ if (atom == __FILE__Atom) {
+ yylvalpp->sc_int = GetStringNumber();
+ sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int);
+ UngetToken(CPP_INTCONSTANT, yylvalpp);
+ return 1;
+ }
+ if (atom == __VERSION__Atom) {
+ strcpy(yylvalpp->symbol_name,ESSL_VERSION_STRING);
+ yylvalpp->sc_int = atoi(yylvalpp->symbol_name);
+ UngetToken(CPP_INTCONSTANT, yylvalpp);
+ return 1;
+ }
+ if (!sym || sym->details.mac.undef) return 0;
+ if (sym->details.mac.busy) return 0; // no recursive expansions
+ in = malloc(sizeof(*in));
+ memset(in, 0, sizeof(*in));
+ in->base.scan = (void *)macro_scan;
+ in->base.line = cpp->currentInput->line;
+ in->base.name = cpp->currentInput->name;
+ in->mac = &sym->details.mac;
+ if (sym->details.mac.args) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token != '(') {
+ UngetToken(token, yylvalpp);
+ yylvalpp->sc_ident = atom;
+ return 0;
+ }
+ in->args = malloc(in->mac->argc * sizeof(TokenStream *));
+ for (i=0; i<in->mac->argc; i++)
+ in->args[i] = NewTokenStream("macro arg", 0);
+ i=0;j=0;
+ do{
+ depth = 0;
+ while(1) {
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token <= 0) {
+ StoreStr("EOF in Macro ");
+ StoreStr(GetStringOfAtom(atable,atom));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ return 1;
+ }
+ if((in->mac->argc==0) && (token!=')')) break;
+ if (depth == 0 && (token == ',' || token == ')')) break;
+ if (token == '(') depth++;
+ if (token == ')') depth--;
+ RecordToken(in->args[i], token, yylvalpp);
+ j=1;
+ }
+ if (token == ')') {
+ if((in->mac->argc==1) &&j==0)
+ break;
+ i++;
+ break;
+ }
+ i++;
+ }while(i < in->mac->argc);
+
+ if (i < in->mac->argc) {
+ StoreStr("Too few args in Macro ");
+ StoreStr(GetStringOfAtom(atable,atom));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ } else if (token != ')') {
+ depth=0;
+ while (token >= 0 && (depth > 0 || token != ')')) {
+ if (token == ')') depth--;
+ token = cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+ if (token == '(') depth++;
+ }
+
+ if (token <= 0) {
+ StoreStr("EOF in Macro ");
+ StoreStr(GetStringOfAtom(atable,atom));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ return 1;
+ }
+ StoreStr("Too many args in Macro ");
+ StoreStr(GetStringOfAtom(atable,atom));
+ message=GetStrfromTStr();
+ CPPShInfoLogMsg(message);
+ ResetTString();
+ }
+ for (i=0; i<in->mac->argc; i++) {
+ in->args[i] = PrescanMacroArg(in->args[i], yylvalpp);
+ }
+ }
+#if 0
+ printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file),
+ loc.line, GetAtomString(atable, atom));
+ for (i=0; i<in->mac->argc; i++) {
+ printf("\targ %s = '", GetAtomString(atable, in->mac->args[i]));
+ DumpTokenStream(stdout, in->args[i]);
+ printf("'\n");
+ }
+#endif
+ /*retain the input source*/
+ in->base.prev = cpp->currentInput;
+ sym->details.mac.busy = 1;
+ RewindTokenStream(sym->details.mac.body);
+ cpp->currentInput = &in->base;
+ return 1;
+} // MacroExpand
+
+int ChkCorrectElseNesting(void)
+{
+ // sanity check to make sure elsetracker is in a valid range
+ if (cpp->elsetracker < 0 || cpp->elsetracker >= MAX_IF_NESTING) {
+ return 0;
+ }
+
+ if (cpp->elsedepth[cpp->elsetracker] == 0) {
+ cpp->elsedepth[cpp->elsetracker] = 1;
+ return 1;
+ }
+ return 0;
+}
+
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cpp.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cpp.h
new file mode 100644
index 000000000..db4c184ae
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cpp.h
@@ -0,0 +1,86 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// cpp.h
+//
+
+#if !defined(__CPP_H)
+#define __CPP_H 1
+
+#include "compiler/preprocessor/parser.h"
+#include "compiler/preprocessor/tokens.h"
+
+int InitCPP(void);
+int FinalCPP(void);
+int readCPPline(yystypepp * yylvalpp);
+int MacroExpand(int atom, yystypepp * yylvalpp);
+int ChkCorrectElseNesting(void);
+
+typedef struct MacroSymbol {
+ int argc;
+ int *args;
+ TokenStream *body;
+ unsigned busy:1;
+ unsigned undef:1;
+} MacroSymbol;
+
+void FreeMacro(MacroSymbol *);
+void PredefineIntMacro(const char *name, int value);
+
+void CPPDebugLogMsg(const char *msg); // Prints information into debug log
+void CPPShInfoLogMsg(const char*); // Store cpp Err Msg into Sh.Info.Log
+void CPPWarningToInfoLog(const char *msg); // Prints warning messages into info log
+void HandlePragma(const char**, int numTokens); // #pragma directive container.
+void ResetTString(void); // #error Message as TString.
+void CPPErrorToInfoLog(char*); // Stick all cpp errors into Sh.Info.log .
+void StoreStr(char*); // Store the TString in Parse Context.
+void SetLineNumber(int); // Set line number.
+void SetStringNumber(int); // Set string number.
+int GetLineNumber(void); // Get the current String Number.
+int GetStringNumber(void); // Get the current String Number.
+const char* GetStrfromTStr(void); // Convert TString to String.
+void updateExtensionBehavior(const char* extName, const char* behavior);
+int FreeCPP(void);
+
+#endif // !(defined(__CPP_H)
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cppstruct.c b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cppstruct.c
new file mode 100644
index 000000000..58cff3109
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/cppstruct.c
@@ -0,0 +1,152 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// cppstruct.c
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "compiler/preprocessor/slglobals.h"
+
+CPPStruct *cpp = NULL;
+static int refCount = 0;
+
+int InitPreprocessor(void);
+int ResetPreprocessor(void);
+int FreeCPPStruct(void);
+int FinalizePreprocessor(void);
+
+/*
+ * InitCPPStruct() - Initilaize the CPP structure.
+ *
+ */
+
+int InitCPPStruct(void)
+{
+ int len;
+ char *p;
+
+ cpp = (CPPStruct *) malloc(sizeof(CPPStruct));
+ if (cpp == NULL)
+ return 0;
+
+ refCount++;
+
+ // Initialize public members:
+ cpp->pLastSourceLoc = &cpp->lastSourceLoc;
+
+ p = (char *) &cpp->options;
+ len = sizeof(cpp->options);
+ while (--len >= 0)
+ p[len] = 0;
+
+ ResetPreprocessor();
+ return 1;
+} // InitCPPStruct
+
+int ResetPreprocessor(void)
+{
+ // Initialize private members:
+
+ cpp->lastSourceLoc.file = 0;
+ cpp->lastSourceLoc.line = 0;
+ cpp->pC = 0;
+ cpp->CompileError = 0;
+ cpp->ifdepth = 0;
+ for(cpp->elsetracker = 0; cpp->elsetracker < MAX_IF_NESTING; cpp->elsetracker++)
+ cpp->elsedepth[cpp->elsetracker] = 0;
+ cpp->elsetracker = 0;
+ cpp->tokensBeforeEOF = 0;
+ return 1;
+}
+
+//Intializing the Preprocessor.
+
+int InitPreprocessor(void)
+{
+ # define CPP_STUFF true
+ # ifdef CPP_STUFF
+ FreeCPPStruct();
+ InitCPPStruct();
+ cpp->options.Quiet = 1;
+ cpp->options.profileString = "generic";
+ if (!InitAtomTable(atable, 0))
+ return 1;
+ if (!InitScanner(cpp))
+ return 1;
+ # endif
+ return 0;
+}
+
+//FreeCPPStruct() - Free the CPP structure.
+
+int FreeCPPStruct(void)
+{
+ if (refCount)
+ {
+ free(cpp);
+ refCount--;
+ }
+
+ return 1;
+}
+
+//Finalizing the Preprocessor.
+
+int FinalizePreprocessor(void)
+{
+ # define CPP_STUFF true
+ # ifdef CPP_STUFF
+ FreeAtomTable(atable);
+ FreeCPPStruct();
+ FreeScanner();
+ # endif
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////// End of cppstruct.c //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/memory.c b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/memory.c
new file mode 100644
index 000000000..e6fea7aa3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/memory.c
@@ -0,0 +1,154 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _MSC_VER
+#include <stdint.h>
+#endif
+
+#include "compiler/preprocessor/memory.h"
+
+// default alignment and chunksize, if called with 0 arguments
+#define CHUNKSIZE (64*1024)
+#define ALIGN 8
+
+// we need to call the `real' malloc and free, not our replacements
+#undef malloc
+#undef free
+
+struct chunk {
+ struct chunk *next;
+};
+
+struct cleanup {
+ struct cleanup *next;
+ void (*fn)(void *);
+ void *arg;
+};
+
+struct MemoryPool_rec {
+ struct chunk *next;
+ uintptr_t free, end;
+ size_t chunksize;
+ uintptr_t alignmask;
+ struct cleanup *cleanup;
+};
+
+MemoryPool *mem_CreatePool(size_t chunksize, unsigned int align)
+{
+ MemoryPool *pool;
+
+ if (align == 0) align = ALIGN;
+ if (chunksize == 0) chunksize = CHUNKSIZE;
+ if (align & (align-1)) return 0;
+ if (chunksize < sizeof(MemoryPool)) return 0;
+ if (chunksize & (align-1)) return 0;
+ if (!(pool = malloc(chunksize))) return 0;
+ pool->next = 0;
+ pool->chunksize = chunksize;
+ pool->alignmask = (uintptr_t)(align)-1;
+ pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask;
+ pool->end = (uintptr_t)pool + chunksize;
+ pool->cleanup = 0;
+ return pool;
+}
+
+void mem_FreePool(MemoryPool *pool)
+{
+ struct cleanup *cleanup;
+ struct chunk *p, *next;
+
+ for (cleanup = pool->cleanup; cleanup; cleanup = cleanup->next) {
+ cleanup->fn(cleanup->arg);
+ }
+ for (p = (struct chunk *)pool; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+}
+
+void *mem_Alloc(MemoryPool *pool, size_t size)
+{
+ struct chunk *ch;
+ void *rv = (void *)pool->free;
+ size = (size + pool->alignmask) & ~pool->alignmask;
+ if (size <= 0) size = pool->alignmask;
+ pool->free += size;
+ if (pool->free > pool->end || pool->free < (uintptr_t)rv) {
+ size_t minreq = (size + sizeof(struct chunk) + pool->alignmask)
+ & ~pool->alignmask;
+ pool->free = (uintptr_t)rv;
+ if (minreq >= pool->chunksize) {
+ // request size is too big for the chunksize, so allocate it as
+ // a single chunk of the right size
+ ch = malloc(minreq);
+ if (!ch) return 0;
+ } else {
+ ch = malloc(pool->chunksize);
+ if (!ch) return 0;
+ pool->free = (uintptr_t)ch + minreq;
+ pool->end = (uintptr_t)ch + pool->chunksize;
+ }
+ ch->next = pool->next;
+ pool->next = ch;
+ rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask);
+ }
+ return rv;
+}
+
+int mem_AddCleanup(MemoryPool *pool, void (*fn)(void *), void *arg) {
+ struct cleanup *cleanup;
+
+ pool->free = (pool->free + sizeof(void *) - 1) & ~(sizeof(void *)-1);
+ cleanup = mem_Alloc(pool, sizeof(struct cleanup));
+ if (!cleanup) return -1;
+ cleanup->next = pool->cleanup;
+ cleanup->fn = fn;
+ cleanup->arg = arg;
+ pool->cleanup = cleanup;
+ return 0;
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/memory.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/memory.h
new file mode 100644
index 000000000..b3ae2f963
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/memory.h
@@ -0,0 +1,56 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+#ifndef __MEMORY_H
+#define __MEMORY_H
+
+typedef struct MemoryPool_rec MemoryPool;
+
+extern MemoryPool *mem_CreatePool(size_t chunksize, unsigned int align);
+extern void mem_FreePool(MemoryPool *);
+extern void *mem_Alloc(MemoryPool *p, size_t size);
+extern void *mem_Realloc(MemoryPool *p, void *old, size_t oldsize, size_t newsize);
+extern int mem_AddCleanup(MemoryPool *p, void (*fn)(void *), void *arg);
+
+#endif /* __MEMORY_H */
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/parser.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/parser.h
new file mode 100644
index 000000000..f67342b67
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/parser.h
@@ -0,0 +1,93 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#ifndef BISON_PARSER_H
+# define BISON_PARSER_H
+
+#ifndef yystypepp
+typedef struct {
+ int sc_int;
+ float sc_fval;
+ int sc_ident;
+ char symbol_name[MAX_SYMBOL_NAME_LEN+1];
+} yystypepp;
+
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+# define CPP_AND_OP 257
+# define CPP_SUB_ASSIGN 259
+# define CPP_MOD_ASSIGN 260
+# define CPP_ADD_ASSIGN 261
+# define CPP_DIV_ASSIGN 262
+# define CPP_MUL_ASSIGN 263
+# define CPP_EQ_OP 264
+# define CPP_XOR_OP 265
+# define ERROR_SY 266
+# define CPP_FLOATCONSTANT 267
+# define CPP_GE_OP 268
+# define CPP_RIGHT_OP 269
+# define CPP_IDENTIFIER 270
+# define CPP_INTCONSTANT 271
+# define CPP_LE_OP 272
+# define CPP_LEFT_OP 273
+# define CPP_DEC_OP 274
+# define CPP_NE_OP 275
+# define CPP_OR_OP 276
+# define CPP_INC_OP 277
+# define CPP_STRCONSTANT 278
+# define CPP_TYPEIDENTIFIER 279
+
+# define FIRST_USER_TOKEN_SY 289
+
+# define CPP_RIGHT_ASSIGN 280
+# define CPP_LEFT_ASSIGN 281
+# define CPP_AND_ASSIGN 282
+# define CPP_OR_ASSIGN 283
+# define CPP_XOR_ASSIGN 284
+# define CPP_LEFT_BRACKET 285
+# define CPP_RIGHT_BRACKET 286
+# define CPP_LEFT_BRACE 287
+# define CPP_RIGHT_BRACE 288
+
+#endif /* not BISON_PARSER_H */
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/preprocess.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/preprocess.h
new file mode 100644
index 000000000..88d196ffe
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/preprocess.h
@@ -0,0 +1,51 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+
+#include "compiler/preprocessor/slglobals.h"
+extern CPPStruct *cpp;
+int InitCPPStruct(void);
+int InitScanner(CPPStruct *cpp);
+int InitAtomTable(AtomTable *atable, int htsize);
+int ScanFromString(const char *s);
+char* GetStringOfAtom(AtomTable *atable, int atom);
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/scanner.c b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/scanner.c
new file mode 100644
index 000000000..deedb43f5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/scanner.c
@@ -0,0 +1,688 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// scanner.c
+//
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if 0
+ #include <ieeefp.h>
+#else
+ #define isinff(x) (((*(int *)&(x) & 0x7f800000L)==0x7f800000L) && \
+ ((*(int *)&(x) & 0x007fffffL)==0000000000L))
+#endif
+
+#include "compiler/preprocessor/slglobals.h"
+#include "compiler/util.h"
+
+typedef struct StringInputSrc {
+ InputSrc base;
+ char *p;
+} StringInputSrc;
+
+static int eof_scan(InputSrc *is, yystypepp * yylvalpp)
+{
+ return EOF;
+} // eof_scan
+
+static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) {}
+
+static InputSrc eof_inputsrc = { 0, &eof_scan, &eof_scan, &noop };
+
+static int byte_scan(InputSrc *, yystypepp * yylvalpp);
+
+#define EOL_SY '\n'
+
+#if defined(_MSC_VER)
+ #define DBG_BREAKPOINT() __asm int 3
+#elif defined(_M_AMD64)
+ #define DBG_BREAKPOINT() assert(!"Dbg_Breakpoint");
+#else
+ #define DBG_BREAKPOINT()
+#endif
+
+#if defined(_MSC_VER) && !defined(_M_AMD64)
+ __int64 RDTSC ( void ) {
+
+ __int64 v;
+
+ __asm __emit 0x0f
+ __asm __emit 0x31
+ __asm mov dword ptr v, eax
+ __asm mov dword ptr v+4, edx
+
+ return v;
+ }
+#endif
+
+
+int InitScanner(CPPStruct *cpp)
+{
+ // Add various atoms needed by the CPP line scanner:
+ if (!InitCPP())
+ return 0;
+
+ cpp->mostRecentToken = 0;
+ cpp->tokenLoc = &cpp->ltokenLoc;
+
+ cpp->ltokenLoc.file = 0;
+ cpp->ltokenLoc.line = 0;
+
+ cpp->currentInput = &eof_inputsrc;
+ cpp->previous_token = '\n';
+ cpp->pastFirstStatement = 0;
+
+ return 1;
+} // InitScanner
+
+int FreeScanner(void)
+{
+ return (FreeCPP());
+}
+
+/*
+ * str_getch()
+ * takes care of reading from multiple strings.
+ * returns the next-char from the input stream.
+ * returns EOF when the complete shader is parsed.
+ */
+static int str_getch(StringInputSrc *in)
+{
+ for(;;){
+ if (*in->p){
+ if (*in->p == '\n') {
+ in->base.line++;
+ IncLineNumber();
+ }
+ return *in->p++;
+ }
+ if(++(cpp->PaWhichStr) < cpp->PaArgc){
+ free(in);
+ SetStringNumber(cpp->PaWhichStr);
+ SetLineNumber(1);
+ ScanFromString(cpp->PaArgv[cpp->PaWhichStr]);
+ in=(StringInputSrc*)cpp->currentInput;
+ continue;
+ }
+ else{
+ cpp->currentInput = in->base.prev;
+ cpp->PaWhichStr=0;
+ free(in);
+ return EOF;
+ }
+ }
+} // str_getch
+
+static void str_ungetch(StringInputSrc *in, int ch, yystypepp *type) {
+ if (in->p[-1] == ch)in->p--;
+ else {
+ *(in->p)='\0'; //this would take care of shifting to the previous string.
+ cpp->PaWhichStr--;
+ }
+ if (ch == '\n') {
+ in->base.line--;
+ DecLineNumber();
+ }
+} // str_ungetch
+
+int ScanFromString(const char *s)
+{
+
+ StringInputSrc *in = malloc(sizeof(StringInputSrc));
+ memset(in, 0, sizeof(StringInputSrc));
+ in->p = (char*) s;
+ in->base.line = 1;
+ in->base.scan = byte_scan;
+ in->base.getch = (int (*)(InputSrc *, yystypepp *))str_getch;
+ in->base.ungetch = (void (*)(InputSrc *, int, yystypepp *))str_ungetch;
+ in->base.prev = cpp->currentInput;
+ cpp->currentInput = &in->base;
+
+ return 1;
+} // ScanFromString;
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Floating point constants: /////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+#define APPEND_CHAR_S(ch, str, len, max_len) \
+ if (len < max_len) { \
+ str[len++] = ch; \
+ } else if (!alreadyComplained) { \
+ CPPErrorToInfoLog("BUFFER OVERFLOW"); \
+ alreadyComplained = 1; \
+ }
+
+/*
+ * lFloatConst() - Scan a floating point constant. Assumes that the scanner
+ * has seen at least one digit, followed by either a decimal '.' or the
+ * letter 'e'.
+ * ch - '.' or 'e'
+ * len - length of string already copied into yylvalpp->symbol_name.
+ */
+
+static int lFloatConst(int ch, int len, yystypepp * yylvalpp)
+{
+ int alreadyComplained = 0;
+ assert((ch == '.') || (ch == 'e') || (ch == 'E'));
+
+ if (ch == '.') {
+ do {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while (ch >= '0' && ch <= '9');
+ }
+
+ // Exponent:
+ if (ch == 'e' || ch == 'E') {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '+') {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } else if (ch == '-') {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ }
+ if (ch >= '0' && ch <= '9') {
+ while (ch >= '0' && ch <= '9') {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ }
+ } else {
+ CPPErrorToInfoLog("EXPONENT INVALID");
+ }
+ }
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ yylvalpp->sc_fval = (float) atof_dot(yylvalpp->symbol_name);
+ if (isinff(yylvalpp->sc_fval)) {
+ CPPErrorToInfoLog("FLOAT CONSTANT OVERFLOW");
+ }
+ return CPP_FLOATCONSTANT;
+} // lFloatConst
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////// Normal Scanner //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+static int byte_scan(InputSrc *in, yystypepp * yylvalpp)
+{
+ char string_val[MAX_STRING_LEN + 1];
+ int alreadyComplained = 0;
+ int len, ch, ii, ival = 0;
+
+ for (;;) {
+ yylvalpp->sc_int = 0;
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+
+ while (ch == ' ' || ch == '\t' || ch == '\r') {
+ yylvalpp->sc_int = 1;
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ }
+
+ cpp->ltokenLoc.file = cpp->currentInput->name;
+ cpp->ltokenLoc.line = cpp->currentInput->line;
+ alreadyComplained = 0;
+ len = 0;
+ switch (ch) {
+ default:
+ return ch; // Single character token
+ case EOF:
+ return -1;
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y':
+ case 'Z': case '_':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y':
+ case 'z':
+ do {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
+ ch == '_');
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ yylvalpp->sc_ident = LookUpAddString(atable, yylvalpp->symbol_name);
+ return CPP_IDENTIFIER;
+ break;
+ case '0':
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == 'x' || ch == 'X') { // hexadecimal integer constants
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if ((ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'F') ||
+ (ch >= 'a' && ch <= 'f'))
+ {
+ ival = 0;
+ do {
+ if ((ival <= 0x0fffffff) && (len < MAX_SYMBOL_NAME_LEN)) {
+ yylvalpp->symbol_name[len++] = ch;
+ if (ch >= '0' && ch <= '9') {
+ ii = ch - '0';
+ } else if (ch >= 'A' && ch <= 'F') {
+ ii = ch - 'A' + 10;
+ } else {
+ ii = ch - 'a' + 10;
+ }
+ ival = (ival << 4) | ii;
+ } else if (!alreadyComplained) {
+ CPPErrorToInfoLog("HEX CONSTANT OVERFLOW");
+ alreadyComplained = 1;
+ }
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while ((ch >= '0' && ch <= '9') ||
+ (ch >= 'A' && ch <= 'F') ||
+ (ch >= 'a' && ch <= 'f'));
+ } else {
+ CPPErrorToInfoLog("HEX CONSTANT INVALID");
+ }
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ yylvalpp->sc_int = ival;
+ return CPP_INTCONSTANT;
+ } else if (ch >= '0' && ch <= '7') { // octal integer constants
+ ival = 0;
+ do {
+ if ((ival <= 0x1fffffff) && (len < MAX_SYMBOL_NAME_LEN)) {
+ yylvalpp->symbol_name[len++] = ch;
+ ii = ch - '0';
+ ival = (ival << 3) | ii;
+ } else if (!alreadyComplained) {
+ CPPErrorToInfoLog("OCT CONSTANT OVERFLOW");
+ alreadyComplained = 1;
+ }
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while (ch >= '0' && ch <= '7');
+ if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'h' || ch == 'x'|| ch == 'E')
+ return lFloatConst(ch, len, yylvalpp);
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ yylvalpp->sc_int = ival;
+ return CPP_INTCONSTANT;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ ch = '0';
+ }
+ // Fall through...
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ do {
+ APPEND_CHAR_S(ch, yylvalpp->symbol_name, len, MAX_SYMBOL_NAME_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while (ch >= '0' && ch <= '9');
+ if (ch == '.' || ch == 'e' || ch == 'E') {
+ return lFloatConst(ch, len, yylvalpp);
+ } else {
+ assert(len <= MAX_SYMBOL_NAME_LEN);
+ yylvalpp->symbol_name[len] = '\0';
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ ival = 0;
+ for (ii = 0; ii < len; ii++) {
+ ch = yylvalpp->symbol_name[ii] - '0';
+ ival = ival*10 + ch;
+ if ((ival > 214748364) || (ival == 214748364 && ch >= 8)) {
+ CPPErrorToInfoLog("INTEGER CONSTANT OVERFLOW");
+ break;
+ }
+ }
+ yylvalpp->sc_int = ival;
+ if(ival==0)
+ strcpy(yylvalpp->symbol_name,"0");
+ return CPP_INTCONSTANT;
+ }
+ break;
+ case '-':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '-') {
+ return CPP_DEC_OP;
+ } else if (ch == '=') {
+ return CPP_SUB_ASSIGN;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '-';
+ }
+ case '+':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '+') {
+ return CPP_INC_OP;
+ } else if (ch == '=') {
+ return CPP_ADD_ASSIGN;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '+';
+ }
+ case '*':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '=') {
+ return CPP_MUL_ASSIGN;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '*';
+ }
+ case '%':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '=') {
+ return CPP_MOD_ASSIGN;
+ } else if (ch == '>'){
+ return CPP_RIGHT_BRACE;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '%';
+ }
+ case ':':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '>') {
+ return CPP_RIGHT_BRACKET;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return ':';
+ }
+ case '^':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '^') {
+ return CPP_XOR_OP;
+ } else {
+ if (ch == '=')
+ return CPP_XOR_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '^';
+ }
+ }
+
+ case '=':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '=') {
+ return CPP_EQ_OP;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '=';
+ }
+ case '!':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '=') {
+ return CPP_NE_OP;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '!';
+ }
+ case '|':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '|') {
+ return CPP_OR_OP;
+ } else {
+ if (ch == '=')
+ return CPP_OR_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '|';
+ }
+ }
+ case '&':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '&') {
+ return CPP_AND_OP;
+ } else {
+ if (ch == '=')
+ return CPP_AND_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '&';
+ }
+ }
+ case '<':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '<') {
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if(ch == '=')
+ return CPP_LEFT_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return CPP_LEFT_OP;
+ }
+ } else {
+ if (ch == '=') {
+ return CPP_LE_OP;
+ } else {
+ if (ch == '%')
+ return CPP_LEFT_BRACE;
+ else if (ch == ':')
+ return CPP_LEFT_BRACKET;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '<';
+ }
+ }
+ }
+ case '>':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '>') {
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if(ch == '=')
+ return CPP_RIGHT_ASSIGN;
+ else{
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return CPP_RIGHT_OP;
+ }
+ } else {
+ if (ch == '=') {
+ return CPP_GE_OP;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '>';
+ }
+ }
+ case '.':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch >= '0' && ch <= '9') {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return lFloatConst('.', 0, yylvalpp);
+ } else {
+ if (ch == '.') {
+ return -1; // Special EOF hack
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '.';
+ }
+ }
+ case '/':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == '/') {
+ do {
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ } while (ch != '\n' && ch != EOF);
+ if (ch == EOF)
+ return -1;
+ return '\n';
+ } else if (ch == '*') {
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ do {
+ while (ch != '*') {
+ if (ch == EOF) {
+ CPPErrorToInfoLog("EOF IN COMMENT");
+ return -1;
+ }
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ }
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ if (ch == EOF) {
+ CPPErrorToInfoLog("EOF IN COMMENT");
+ return -1;
+ }
+ } while (ch != '/');
+ // Go try it again...
+ } else if (ch == '=') {
+ return CPP_DIV_ASSIGN;
+ } else {
+ cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp);
+ return '/';
+ }
+ break;
+ case '"':
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ while (ch != '"' && ch != '\n' && ch != EOF) {
+ if (ch == '\\') {
+ CPPErrorToInfoLog("The line continuation character (\\) is not part of the OpenGL ES Shading Language");
+ return -1;
+ }
+ APPEND_CHAR_S(ch, string_val, len, MAX_STRING_LEN);
+ ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp);
+ };
+ assert(len <= MAX_STRING_LEN);
+ string_val[len] = '\0';
+ if (ch == '"') {
+ yylvalpp->sc_ident = LookUpAddString(atable, string_val);
+ return CPP_STRCONSTANT;
+ } else {
+ CPPErrorToInfoLog("EOL IN STRING");
+ return ERROR_SY;
+ }
+ break;
+ }
+ }
+} // byte_scan
+
+int yylex_CPP(char* buf, int maxSize)
+{
+ yystypepp yylvalpp;
+ int token = '\n';
+
+ for(;;) {
+
+ char* tokenString = 0;
+ token = cpp->currentInput->scan(cpp->currentInput, &yylvalpp);
+ if(check_EOF(token))
+ return 0;
+ if (token < 0) {
+ // This check may need to be improved to support UTF-8
+ // characters in comments.
+ CPPErrorToInfoLog("preprocessor encountered non-ASCII character in shader source");
+ return 0;
+ }
+ if (token == '#') {
+ if (cpp->previous_token == '\n'|| cpp->previous_token == 0) {
+ token = readCPPline(&yylvalpp);
+ if(check_EOF(token))
+ return 0;
+ continue;
+ } else {
+ CPPErrorToInfoLog("preprocessor command must not be preceded by any other statement in that line");
+ return 0;
+ }
+ }
+ cpp->previous_token = token;
+ // expand macros
+ if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp.sc_ident, &yylvalpp)) {
+ cpp->pastFirstStatement = 1;
+ continue;
+ }
+
+ if (token == '\n')
+ continue;
+ cpp->pastFirstStatement = 1;
+
+ if (token == CPP_IDENTIFIER) {
+ tokenString = GetStringOfAtom(atable,yylvalpp.sc_ident);
+ } else if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){
+ tokenString = yylvalpp.symbol_name;
+ } else {
+ tokenString = GetStringOfAtom(atable,token);
+ }
+
+ if (tokenString) {
+ int len = strlen(tokenString);
+ cpp->tokensBeforeEOF = 1;
+ if (len >= maxSize) {
+ return maxSize;
+ } else if (len > 0) {
+ strcpy(buf, tokenString);
+ return len;
+ }
+
+ return 0;
+ }
+ }
+
+ return 0;
+} // yylex
+
+//Checks if the token just read is EOF or not.
+int check_EOF(int token)
+{
+ if(token==-1){
+ if(cpp->ifdepth >0){
+ CPPErrorToInfoLog("#endif missing!! Compilation stopped");
+ cpp->CompileError=1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////// End of scanner.c //////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/scanner.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/scanner.h
new file mode 100644
index 000000000..33306e523
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/scanner.h
@@ -0,0 +1,84 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// scanner.h
+//
+
+#if !defined(__SCANNER_H)
+#define __SCANNER_H 1
+
+// These lengths do not include the NULL terminator.
+#define MAX_SYMBOL_NAME_LEN 256
+#define MAX_STRING_LEN 511
+
+#include "compiler/preprocessor/parser.h"
+
+// Not really atom table stuff but needed first...
+
+typedef struct SourceLoc_Rec {
+ unsigned short file, line;
+} SourceLoc;
+
+int yylex_CPP(char* buf, int maxSize);
+
+typedef struct InputSrc {
+ struct InputSrc *prev;
+ int (*scan)(struct InputSrc *, yystypepp *);
+ int (*getch)(struct InputSrc *, yystypepp *);
+ void (*ungetch)(struct InputSrc *, int, yystypepp *);
+ int name; /* atom */
+ int line;
+} InputSrc;
+
+int InitScanner(CPPStruct *cpp); // Intialise the cpp scanner.
+int ScanFromString(const char *); // Start scanning the input from the string mentioned.
+int check_EOF(int); // check if we hit a EOF abruptly
+void CPPErrorToInfoLog(char *); // sticking the msg,line into the Shader's.Info.log
+void SetLineNumber(int);
+void SetStringNumber(int);
+void IncLineNumber(void);
+void DecLineNumber(void);
+int FreeScanner(void); // Free the cpp scanner
+#endif // !(defined(__SCANNER_H)
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/slglobals.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/slglobals.h
new file mode 100644
index 000000000..463462664
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/slglobals.h
@@ -0,0 +1,82 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// slglobals.h
+//
+
+#if !defined(__SLGLOBALS_H)
+#define __SLGLOBALS_H 1
+
+typedef struct CPPStruct_Rec CPPStruct;
+
+extern CPPStruct *cpp;
+
+#undef CPPC_DEBUG_THE_COMPILER
+#if defined(_DEBUG)
+#define CPPC_DEBUG_THE_COMPILER 1
+#endif
+
+#undef CPPC_ENABLE_TOOLS
+#define CPPC_ENABLE_TOOLS 1
+
+#include "compiler/preprocessor/memory.h"
+#include "compiler/preprocessor/atom.h"
+#include "compiler/preprocessor/scanner.h"
+#include "compiler/preprocessor/cpp.h"
+#include "compiler/preprocessor/tokens.h"
+#include "compiler/preprocessor/symbols.h"
+#include "compiler/preprocessor/compile.h"
+#if !defined(NO_PARSER)
+#include "compiler/preprocessor/parser.h"
+#endif
+
+#if !defined(NULL)
+#define NULL 0
+#endif
+
+#endif // !(defined(__SLGLOBALS_H)
+
+
+
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/symbols.c b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/symbols.c
new file mode 100644
index 000000000..5baedf52f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/symbols.c
@@ -0,0 +1,284 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// symbols.c
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "compiler/preprocessor/slglobals.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////// Symbol Table Variables: ///////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+Scope *ScopeList = NULL;
+Scope *CurrentScope = NULL;
+Scope *GlobalScope = NULL;
+
+static void unlinkScope(void *_scope) {
+ Scope *scope = _scope;
+
+ if (scope->next)
+ scope->next->prev = scope->prev;
+ if (scope->prev)
+ scope->prev->next = scope->next;
+ else
+ ScopeList = scope->next;
+}
+
+/*
+ * NewScope()
+ *
+ */
+Scope *NewScopeInPool(MemoryPool *pool)
+{
+ Scope *lScope;
+
+ lScope = mem_Alloc(pool, sizeof(Scope));
+ lScope->pool = pool;
+ lScope->parent = NULL;
+ lScope->funScope = NULL;
+ lScope->symbols = NULL;
+
+ lScope->level = 0;
+
+ lScope->programs = NULL;
+ if ((lScope->next = ScopeList))
+ ScopeList->prev = lScope;
+ lScope->prev = 0;
+ ScopeList = lScope;
+ mem_AddCleanup(pool, unlinkScope, lScope);
+ return lScope;
+} // NewScope
+
+/*
+ * PushScope()
+ *
+ */
+
+void PushScope(Scope *fScope)
+{
+ Scope *lScope;
+
+ if (CurrentScope) {
+ fScope->level = CurrentScope->level + 1;
+ if (fScope->level == 1) {
+ if (!GlobalScope) {
+ /* HACK - CTD -- if GlobalScope==NULL and level==1, we're
+ * defining a function in the superglobal scope. Things
+ * will break if we leave the level as 1, so we arbitrarily
+ * set it to 2 */
+ fScope->level = 2;
+ }
+ }
+ if (fScope->level >= 2) {
+ lScope = fScope;
+ while (lScope->level > 2)
+ lScope = lScope->next;
+ fScope->funScope = lScope;
+ }
+ } else {
+ fScope->level = 0;
+ }
+ fScope->parent = CurrentScope;
+ CurrentScope = fScope;
+} // PushScope
+
+/*
+ * PopScope()
+ *
+ */
+
+Scope *PopScope(void)
+{
+ Scope *lScope;
+
+ lScope = CurrentScope;
+ if (CurrentScope)
+ CurrentScope = CurrentScope->parent;
+ return lScope;
+} // PopScope
+
+/*
+ * NewSymbol() - Allocate a new symbol node;
+ *
+ */
+
+Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind)
+{
+ Symbol *lSymb;
+ char *pch;
+ unsigned int ii;
+
+ lSymb = (Symbol *) mem_Alloc(fScope->pool, sizeof(Symbol));
+ lSymb->left = NULL;
+ lSymb->right = NULL;
+ lSymb->next = NULL;
+ lSymb->name = name;
+ lSymb->loc = *loc;
+ lSymb->kind = kind;
+
+ // Clear union area:
+
+ pch = (char *) &lSymb->details;
+ for (ii = 0; ii < sizeof(lSymb->details); ii++)
+ *pch++ = 0;
+ return lSymb;
+} // NewSymbol
+
+/*
+ * lAddToTree() - Using a binary tree is not a good idea for basic atom values because they
+ * are generated in order. We'll fix this later (by reversing the bit pattern).
+ */
+
+static void lAddToTree(Symbol **fSymbols, Symbol *fSymb)
+{
+ Symbol *lSymb;
+ int lrev, frev;
+
+ lSymb = *fSymbols;
+ if (lSymb) {
+ frev = GetReversedAtom(atable, fSymb->name);
+ while (lSymb) {
+ lrev = GetReversedAtom(atable, lSymb->name);
+ if (lrev == frev) {
+ CPPErrorToInfoLog("GetAtomString(atable, fSymb->name)");
+ break;
+ } else {
+ if (lrev > frev) {
+ if (lSymb->left) {
+ lSymb = lSymb->left;
+ } else {
+ lSymb->left = fSymb;
+ break;
+ }
+ } else {
+ if (lSymb->right) {
+ lSymb = lSymb->right;
+ } else {
+ lSymb->right = fSymb;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ *fSymbols = fSymb;
+ }
+} // lAddToTree
+
+
+/*
+ * AddSymbol() - Add a variable, type, or function name to a scope.
+ *
+ */
+
+Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind)
+{
+ Symbol *lSymb;
+
+ if (!fScope)
+ fScope = CurrentScope;
+ lSymb = NewSymbol(loc, fScope, atom, kind);
+ lAddToTree(&fScope->symbols, lSymb);
+ return lSymb;
+} // AddSymbol
+
+
+/*********************************************************************************************/
+/************************************ Symbol Semantic Functions ******************************/
+/*********************************************************************************************/
+
+/*
+ * LookUpLocalSymbol()
+ *
+ */
+
+Symbol *LookUpLocalSymbol(Scope *fScope, int atom)
+{
+ Symbol *lSymb;
+ int rname, ratom;
+
+ ratom = GetReversedAtom(atable, atom);
+ if (!fScope)
+ fScope = CurrentScope;
+ lSymb = fScope->symbols;
+ while (lSymb) {
+ rname = GetReversedAtom(atable, lSymb->name);
+ if (rname == ratom) {
+ return lSymb;
+ } else {
+ if (rname > ratom) {
+ lSymb = lSymb->left;
+ } else {
+ lSymb = lSymb->right;
+ }
+ }
+ }
+ return NULL;
+} // LookUpLocalSymbol
+
+/*
+ * LookUpSymbol()
+ *
+ */
+
+Symbol *LookUpSymbol(Scope *fScope, int atom)
+{
+ Symbol *lSymb;
+
+ if (!fScope)
+ fScope = CurrentScope;
+ while (fScope) {
+ lSymb = LookUpLocalSymbol(fScope, atom);
+ if (lSymb)
+ return lSymb;
+ fScope = fScope->parent;
+ }
+ return NULL;
+} // LookUpSymbol
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/symbols.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/symbols.h
new file mode 100644
index 000000000..c19f79c97
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/symbols.h
@@ -0,0 +1,112 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// symbols.h
+//
+
+#if !defined(__SYMBOLS_H)
+#define __SYMBOLS_H 1
+
+#include "compiler/preprocessor/memory.h"
+
+typedef enum symbolkind {
+ MACRO_S
+} symbolkind;
+
+// Typedefs for things defined here in "symbols.h":
+
+typedef struct Scope_Rec Scope;
+typedef struct Symbol_Rec Symbol;
+
+typedef struct SymbolList_Rec {
+ struct SymbolList_Rec *next;
+ Symbol *symb;
+} SymbolList;
+
+struct Scope_Rec {
+ Scope *next, *prev; // doubly-linked list of all scopes
+ Scope *parent;
+ Scope *funScope; // Points to base scope of enclosing function
+ MemoryPool *pool; // pool used for allocation in this scope
+ Symbol *symbols;
+
+ int level; // 0 = super globals, 1 = globals, etc.
+
+ // Only used at global scope (level 1):
+ SymbolList *programs; // List of programs for this compilation.
+};
+
+
+// Symbol table is a simple binary tree.
+
+#include "compiler/preprocessor/cpp.h" // to get MacroSymbol def
+
+struct Symbol_Rec {
+ Symbol *left, *right;
+ Symbol *next;
+ int name; // Name atom
+ SourceLoc loc;
+ symbolkind kind;
+ union {
+ MacroSymbol mac;
+ } details;
+};
+
+extern Scope *CurrentScope;
+extern Scope *GlobalScope;
+extern Scope *ScopeList;
+
+Scope *NewScopeInPool(MemoryPool *);
+#define NewScope() NewScopeInPool(CurrentScope->pool)
+void PushScope(Scope *fScope);
+Scope *PopScope(void);
+Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind);
+Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind);
+Symbol *LookUpLocalSymbol(Scope *fScope, int atom);
+Symbol *LookUpSymbol(Scope *fScope, int atom);
+void CPPErrorToInfoLog(char *);
+
+
+#endif // !defined(__SYMBOLS_H)
+
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/tokens.c b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/tokens.c
new file mode 100644
index 000000000..aa83d2fce
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/tokens.c
@@ -0,0 +1,436 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// tokens.c
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "compiler/debug.h"
+#include "compiler/preprocessor/slglobals.h"
+#include "compiler/util.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////// Preprocessor and Token Recorder and Playback: ////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+ * idstr()
+ * Copy a string to a malloc'ed block and convert it into something suitable
+ * for an ID
+ *
+ */
+
+static char *idstr(const char *fstr, MemoryPool *pool)
+{
+ size_t len;
+ char *str, *t;
+ const char *f;
+
+ len = strlen(fstr);
+ if (!pool)
+ str = (char *) malloc(len + 1);
+ else
+ str = (char *) mem_Alloc(pool, len + 1);
+
+ for (f=fstr, t=str; *f; f++) {
+ if (isalnum(*f)) *t++ = *f;
+ else if (*f == '.' || *f == '/') *t++ = '_';
+ }
+ *t = 0;
+ return str;
+} // idstr
+
+
+/*
+ * lNewBlock()
+ *
+ */
+
+static TokenBlock *lNewBlock(TokenStream *fTok, MemoryPool *pool)
+{
+ TokenBlock *lBlock;
+
+ if (!pool)
+ lBlock = (TokenBlock *) malloc(sizeof(TokenBlock) + 256);
+ else
+ lBlock = (TokenBlock *) mem_Alloc(pool, sizeof(TokenBlock) + 256);
+ lBlock->count = 0;
+ lBlock->current = 0;
+ lBlock->data = (unsigned char *) lBlock + sizeof(TokenBlock);
+ lBlock->max = 256;
+ lBlock->next = NULL;
+ if (fTok->head) {
+ fTok->current->next = lBlock;
+ } else {
+ fTok->head = lBlock;
+ }
+ fTok->current = lBlock;
+ return lBlock;
+} // lNewBlock
+
+/*
+ * lAddByte()
+ *
+ */
+
+static void lAddByte(TokenStream *fTok, unsigned char fVal)
+{
+ TokenBlock *lBlock;
+ lBlock = fTok->current;
+ if (lBlock->count >= lBlock->max)
+ lBlock = lNewBlock(fTok, 0);
+ lBlock->data[lBlock->count++] = fVal;
+} // lAddByte
+
+
+
+/*
+ * lReadByte() - Get the next byte from a stream.
+ *
+ */
+
+static int lReadByte(TokenStream *pTok)
+{
+ TokenBlock *lBlock;
+ int lval = -1;
+
+ lBlock = pTok->current;
+ if (lBlock) {
+ if (lBlock->current >= lBlock->count) {
+ lBlock = lBlock->next;
+ if (lBlock)
+ lBlock->current = 0;
+ pTok->current = lBlock;
+ }
+ if (lBlock)
+ lval = lBlock->data[lBlock->current++];
+ }
+ return lval;
+} // lReadByte
+
+/////////////////////////////////////// Global Functions://////////////////////////////////////
+
+/*
+ * NewTokenStream()
+ *
+ */
+
+TokenStream *NewTokenStream(const char *name, MemoryPool *pool)
+{
+ TokenStream *pTok;
+
+ if (!pool)
+ pTok = (TokenStream *) malloc(sizeof(TokenStream));
+ else
+ pTok = (TokenStream*)mem_Alloc(pool, sizeof(TokenStream));
+ pTok->next = NULL;
+ pTok->name = idstr(name, pool);
+ pTok->head = NULL;
+ pTok->current = NULL;
+ lNewBlock(pTok, pool);
+ return pTok;
+} // NewTokenStream
+
+/*
+ * DeleteTokenStream()
+ *
+ */
+
+void DeleteTokenStream(TokenStream *pTok)
+{
+ TokenBlock *pBlock, *nBlock;
+
+ if (pTok) {
+ pBlock = pTok->head;
+ while (pBlock) {
+ nBlock = pBlock->next;
+ free(pBlock);
+ pBlock = nBlock;
+ }
+ if (pTok->name)
+ free(pTok->name);
+ free(pTok);
+ }
+} // DeleteTokenStream
+
+/*
+ * RecordToken() - Add a token to the end of a list for later playback or printout.
+ *
+ */
+
+void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp)
+{
+ const char *s;
+ char *str=NULL;
+
+ if (token > 256)
+ lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80));
+ else
+ lAddByte(pTok, (unsigned char)(token & 0x7f));
+ switch (token) {
+ case CPP_IDENTIFIER:
+ case CPP_TYPEIDENTIFIER:
+ case CPP_STRCONSTANT:
+ s = GetAtomString(atable, yylvalpp->sc_ident);
+ while (*s)
+ lAddByte(pTok, (unsigned char) *s++);
+ lAddByte(pTok, 0);
+ break;
+ case CPP_FLOATCONSTANT:
+ case CPP_INTCONSTANT:
+ str=yylvalpp->symbol_name;
+ while (*str){
+ lAddByte(pTok, (unsigned char) *str++);
+ }
+ lAddByte(pTok, 0);
+ break;
+ case '(':
+ lAddByte(pTok, (unsigned char)(yylvalpp->sc_int ? 1 : 0));
+ default:
+ break;
+ }
+} // RecordToken
+
+/*
+ * RewindTokenStream() - Reset a token stream in preperation for reading.
+ *
+ */
+
+void RewindTokenStream(TokenStream *pTok)
+{
+ if (pTok->head) {
+ pTok->current = pTok->head;
+ pTok->current->current = 0;
+ }
+} // RewindTokenStream
+
+/*
+ * ReadToken() - Read the next token from a stream.
+ *
+ */
+
+int ReadToken(TokenStream *pTok, yystypepp * yylvalpp)
+{
+ char symbol_name[MAX_SYMBOL_NAME_LEN + 1];
+ char string_val[MAX_STRING_LEN + 1];
+ int ltoken, len;
+ char ch;
+
+ ltoken = lReadByte(pTok);
+ if (ltoken >= 0) {
+ if (ltoken > 127)
+ ltoken += 128;
+ switch (ltoken) {
+ case CPP_IDENTIFIER:
+ case CPP_TYPEIDENTIFIER:
+ len = 0;
+ ch = lReadByte(pTok);
+ while ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') ||
+ ch == '_')
+ {
+ if (len < MAX_SYMBOL_NAME_LEN) {
+ symbol_name[len++] = ch;
+ ch = lReadByte(pTok);
+ }
+ }
+ symbol_name[len] = '\0';
+ assert(ch == '\0');
+ yylvalpp->sc_ident = LookUpAddString(atable, symbol_name);
+ return CPP_IDENTIFIER;
+ break;
+ case CPP_STRCONSTANT:
+ len = 0;
+ while ((ch = lReadByte(pTok)) != 0)
+ if (len < MAX_STRING_LEN)
+ string_val[len++] = ch;
+ string_val[len] = '\0';
+ yylvalpp->sc_ident = LookUpAddString(atable, string_val);
+ break;
+ case CPP_FLOATCONSTANT:
+ len = 0;
+ ch = lReadByte(pTok);
+ while ((ch >= '0' && ch <= '9')||(ch=='e'||ch=='E'||ch=='.')||(ch=='+'||ch=='-'))
+ {
+ if (len < MAX_SYMBOL_NAME_LEN) {
+ symbol_name[len++] = ch;
+ ch = lReadByte(pTok);
+ }
+ }
+ symbol_name[len] = '\0';
+ assert(ch == '\0');
+ strcpy(yylvalpp->symbol_name,symbol_name);
+ yylvalpp->sc_fval=(float)atof_dot(yylvalpp->symbol_name);
+ break;
+ case CPP_INTCONSTANT:
+ len = 0;
+ ch = lReadByte(pTok);
+ while ((ch >= '0' && ch <= '9'))
+ {
+ if (len < MAX_SYMBOL_NAME_LEN) {
+ symbol_name[len++] = ch;
+ ch = lReadByte(pTok);
+ }
+ }
+ symbol_name[len] = '\0';
+ assert(ch == '\0');
+ strcpy(yylvalpp->symbol_name,symbol_name);
+ yylvalpp->sc_int=atoi(yylvalpp->symbol_name);
+ break;
+ case '(':
+ yylvalpp->sc_int = lReadByte(pTok);
+ break;
+ }
+ return ltoken;
+ }
+ return EOF_SY;
+} // ReadToken
+
+typedef struct TokenInputSrc {
+ InputSrc base;
+ TokenStream *tokens;
+ int (*final)(CPPStruct *);
+} TokenInputSrc;
+
+static int scan_token(TokenInputSrc *in, yystypepp * yylvalpp)
+{
+ int token = ReadToken(in->tokens, yylvalpp);
+ int (*final)(CPPStruct *);
+ cpp->tokenLoc->file = cpp->currentInput->name;
+ cpp->tokenLoc->line = cpp->currentInput->line;
+ if (token == '\n') {
+ in->base.line++;
+ return token;
+ }
+ if (token > 0) return token;
+ cpp->currentInput = in->base.prev;
+ final = in->final;
+ free(in);
+ if (final && !final(cpp)) return -1;
+ return cpp->currentInput->scan(cpp->currentInput, yylvalpp);
+}
+
+int ReadFromTokenStream(TokenStream *ts, int name, int (*final)(CPPStruct *))
+{
+ TokenInputSrc *in = malloc(sizeof(TokenInputSrc));
+ memset(in, 0, sizeof(TokenInputSrc));
+ in->base.name = name;
+ in->base.prev = cpp->currentInput;
+ in->base.scan = (int (*)(InputSrc *, yystypepp *))scan_token;
+ in->base.line = 1;
+ in->tokens = ts;
+ in->final = final;
+ RewindTokenStream(ts);
+ cpp->currentInput = &in->base;
+ return 1;
+}
+
+typedef struct UngotToken {
+ InputSrc base;
+ int token;
+ yystypepp lval;
+} UngotToken;
+
+static int reget_token(UngotToken *t, yystypepp * yylvalpp)
+{
+ int token = t->token;
+ *yylvalpp = t->lval;
+ cpp->currentInput = t->base.prev;
+ free(t);
+ return token;
+}
+
+void UngetToken(int token, yystypepp * yylvalpp) {
+ UngotToken *t = malloc(sizeof(UngotToken));
+ memset(t, 0, sizeof(UngotToken));
+ t->token = token;
+ t->lval = *yylvalpp;
+ t->base.scan = (void *)reget_token;
+ t->base.prev = cpp->currentInput;
+ t->base.name = cpp->currentInput->name;
+ t->base.line = cpp->currentInput->line;
+ cpp->currentInput = &t->base;
+}
+
+
+void DumpTokenStream(FILE *fp, TokenStream *s, yystypepp * yylvalpp) {
+ int token;
+ char str[100];
+
+ if (fp == 0) fp = stdout;
+ RewindTokenStream(s);
+ while ((token = ReadToken(s, yylvalpp)) > 0) {
+ switch (token) {
+ case CPP_IDENTIFIER:
+ case CPP_TYPEIDENTIFIER:
+ sprintf(str, "%s ", GetAtomString(atable, yylvalpp->sc_ident));
+ break;
+ case CPP_STRCONSTANT:
+ sprintf(str, "\"%s\"", GetAtomString(atable, yylvalpp->sc_ident));
+ break;
+ case CPP_FLOATCONSTANT:
+ //printf("%g9.6 ", yylvalpp->sc_fval);
+ break;
+ case CPP_INTCONSTANT:
+ //printf("%d ", yylvalpp->sc_int);
+ break;
+ default:
+ if (token >= 127)
+ sprintf(str, "%s ", GetAtomString(atable, token));
+ else
+ sprintf(str, "%c", token);
+ break;
+ }
+ CPPDebugLogMsg(str);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////// End of tokens.c ///////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/Source/ThirdParty/ANGLE/src/compiler/preprocessor/tokens.h b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/tokens.h
new file mode 100644
index 000000000..8766df9e4
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/preprocessor/tokens.h
@@ -0,0 +1,89 @@
+/****************************************************************************\
+Copyright (c) 2002, NVIDIA Corporation.
+
+NVIDIA Corporation("NVIDIA") supplies this software to you in
+consideration of your agreement to the following terms, and your use,
+installation, modification or redistribution of this NVIDIA software
+constitutes acceptance of these terms. If you do not agree with these
+terms, please do not use, install, modify or redistribute this NVIDIA
+software.
+
+In consideration of your agreement to abide by the following terms, and
+subject to these terms, NVIDIA grants you a personal, non-exclusive
+license, under NVIDIA's copyrights in this original NVIDIA software (the
+"NVIDIA Software"), to use, reproduce, modify and redistribute the
+NVIDIA Software, with or without modifications, in source and/or binary
+forms; provided that if you redistribute the NVIDIA Software, you must
+retain the copyright notice of NVIDIA, this notice and the following
+text and disclaimers in all such redistributions of the NVIDIA Software.
+Neither the name, trademarks, service marks nor logos of NVIDIA
+Corporation may be used to endorse or promote products derived from the
+NVIDIA Software without specific prior written permission from NVIDIA.
+Except as expressly stated in this notice, no other rights or licenses
+express or implied, are granted by NVIDIA herein, including but not
+limited to any patent rights that may be infringed by your derivative
+works or by other works in which the NVIDIA Software may be
+incorporated. No hardware is licensed hereunder.
+
+THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
+INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
+PRODUCTS.
+
+IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
+INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
+OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
+NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
+TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
+NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\****************************************************************************/
+//
+// tokens.h
+//
+
+#if !defined(__TOKENS_H)
+#define __TOKENS_H 1
+
+#include "compiler/preprocessor/parser.h"
+
+#define EOF_SY (-1)
+
+typedef struct TokenBlock_Rec TokenBlock;
+
+typedef struct TokenStream_Rec {
+ struct TokenStream_Rec *next;
+ char *name;
+ TokenBlock *head;
+ TokenBlock *current;
+} TokenStream;
+
+struct TokenBlock_Rec {
+ TokenBlock *next;
+ int current;
+ int count;
+ int max;
+ unsigned char *data;
+};
+
+extern TokenStream stdlib_cpp_stream;
+
+
+TokenStream *NewTokenStream(const char *name, MemoryPool *pool);
+void DeleteTokenStream(TokenStream *pTok);
+void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp);
+void RewindTokenStream(TokenStream *pTok);
+int ReadToken(TokenStream *pTok, yystypepp * yylvalpp);
+int ReadFromTokenStream(TokenStream *pTok, int name, int (*final)(CPPStruct *));
+void UngetToken(int, yystypepp * yylvalpp);
+
+#if defined(CPPC_ENABLE_TOOLS)
+
+void DumpTokenStream(FILE *, TokenStream *, yystypepp * yylvalpp);
+
+#endif // defined(CPPC_ENABLE_TOOLS)
+
+#endif // !defined(__TOKENS_H)
diff --git a/Source/ThirdParty/ANGLE/src/compiler/util.cpp b/Source/ThirdParty/ANGLE/src/compiler/util.cpp
new file mode 100644
index 000000000..b46e4d0e3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/util.cpp
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+#ifdef _MSC_VER
+ #include <locale.h>
+#else
+ #include <sstream>
+#endif
+
+double atof_dot(const char *str)
+{
+#ifdef _MSC_VER
+ _locale_t l = _create_locale(LC_NUMERIC, "C");
+ double result = _atof_l(str, l);
+ _free_locale(l);
+ return result;
+#else
+ double result;
+ std::istringstream s(str);
+ std::locale l("C");
+ s.imbue(l);
+ s >> result;
+ return result;
+#endif
+}
diff --git a/Source/ThirdParty/ANGLE/src/compiler/util.h b/Source/ThirdParty/ANGLE/src/compiler/util.h
new file mode 100644
index 000000000..35288b739
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/compiler/util.h
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#ifndef COMPILER_UTIL_H
+#define COMPILER_UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// atof_dot is like atof but forcing C locale, i.e. forcing '.' as decimal point.
+double atof_dot(const char *str);
+
+#ifdef __cplusplus
+} // end extern "C"
+#endif
+
+#endif // COMPILER_UTIL_H
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Config.cpp b/Source/ThirdParty/ANGLE/src/libEGL/Config.cpp
new file mode 100644
index 000000000..e4dc704a9
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/Config.cpp
@@ -0,0 +1,399 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Config.cpp: Implements the egl::Config class, describing the format, type
+// and size for an egl::Surface. Implements EGLConfig and related functionality.
+// [EGL 1.4] section 3.4 page 15.
+
+#include "libEGL/Config.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "common/debug.h"
+
+using namespace std;
+
+namespace egl
+{
+Config::Config(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight)
+ : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample)
+{
+ set(displayMode, minInterval, maxInterval, renderTargetFormat, depthStencilFormat, multiSample, texWidth, texHeight);
+}
+
+void Config::setDefaults()
+{
+ mBufferSize = 0;
+ mRedSize = 0;
+ mGreenSize = 0;
+ mBlueSize = 0;
+ mLuminanceSize = 0;
+ mAlphaSize = 0;
+ mAlphaMaskSize = 0;
+ mBindToTextureRGB = EGL_DONT_CARE;
+ mBindToTextureRGBA = EGL_DONT_CARE;
+ mColorBufferType = EGL_RGB_BUFFER;
+ mConfigCaveat = EGL_DONT_CARE;
+ mConfigID = EGL_DONT_CARE;
+ mConformant = 0;
+ mDepthSize = 0;
+ mLevel = 0;
+ mMatchNativePixmap = EGL_NONE;
+ mMaxPBufferWidth = 0;
+ mMaxPBufferHeight = 0;
+ mMaxPBufferPixels = 0;
+ mMaxSwapInterval = EGL_DONT_CARE;
+ mMinSwapInterval = EGL_DONT_CARE;
+ mNativeRenderable = EGL_DONT_CARE;
+ mNativeVisualID = 0;
+ mNativeVisualType = EGL_DONT_CARE;
+ mRenderableType = EGL_OPENGL_ES_BIT;
+ mSampleBuffers = 0;
+ mSamples = 0;
+ mStencilSize = 0;
+ mSurfaceType = EGL_WINDOW_BIT;
+ mTransparentType = EGL_NONE;
+ mTransparentRedValue = EGL_DONT_CARE;
+ mTransparentGreenValue = EGL_DONT_CARE;
+ mTransparentBlueValue = EGL_DONT_CARE;
+}
+
+void Config::set(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight)
+{
+ mBindToTextureRGB = EGL_FALSE;
+ mBindToTextureRGBA = EGL_FALSE;
+ switch (renderTargetFormat)
+ {
+ case D3DFMT_A1R5G5B5:
+ mBufferSize = 16;
+ mRedSize = 5;
+ mGreenSize = 5;
+ mBlueSize = 5;
+ mAlphaSize = 1;
+ break;
+ case D3DFMT_A2R10G10B10:
+ mBufferSize = 32;
+ mRedSize = 10;
+ mGreenSize = 10;
+ mBlueSize = 10;
+ mAlphaSize = 2;
+ break;
+ case D3DFMT_A8R8G8B8:
+ mBufferSize = 32;
+ mRedSize = 8;
+ mGreenSize = 8;
+ mBlueSize = 8;
+ mAlphaSize = 8;
+ mBindToTextureRGBA = true;
+ break;
+ case D3DFMT_R5G6B5:
+ mBufferSize = 16;
+ mRedSize = 5;
+ mGreenSize = 6;
+ mBlueSize = 5;
+ mAlphaSize = 0;
+ break;
+ case D3DFMT_X8R8G8B8:
+ mBufferSize = 32;
+ mRedSize = 8;
+ mGreenSize = 8;
+ mBlueSize = 8;
+ mAlphaSize = 0;
+ mBindToTextureRGB = true;
+ break;
+ default:
+ UNREACHABLE(); // Other formats should not be valid
+ }
+
+ mLuminanceSize = 0;
+ mAlphaMaskSize = 0;
+ mColorBufferType = EGL_RGB_BUFFER;
+ mConfigCaveat = (displayMode.Format == renderTargetFormat) ? EGL_NONE : EGL_SLOW_CONFIG;
+ mConfigID = 0;
+ mConformant = EGL_OPENGL_ES2_BIT;
+
+ switch (depthStencilFormat)
+ {
+ case D3DFMT_UNKNOWN:
+ mDepthSize = 0;
+ mStencilSize = 0;
+ break;
+// case D3DFMT_D16_LOCKABLE:
+// mDepthSize = 16;
+// mStencilSize = 0;
+// break;
+ case D3DFMT_D32:
+ mDepthSize = 32;
+ mStencilSize = 0;
+ break;
+ case D3DFMT_D15S1:
+ mDepthSize = 15;
+ mStencilSize = 1;
+ break;
+ case D3DFMT_D24S8:
+ mDepthSize = 24;
+ mStencilSize = 8;
+ break;
+ case D3DFMT_D24X8:
+ mDepthSize = 24;
+ mStencilSize = 0;
+ break;
+ case D3DFMT_D24X4S4:
+ mDepthSize = 24;
+ mStencilSize = 4;
+ break;
+ case D3DFMT_D16:
+ mDepthSize = 16;
+ mStencilSize = 0;
+ break;
+// case D3DFMT_D32F_LOCKABLE:
+// mDepthSize = 32;
+// mStencilSize = 0;
+// break;
+// case D3DFMT_D24FS8:
+// mDepthSize = 24;
+// mStencilSize = 8;
+// break;
+ default:
+ UNREACHABLE();
+ }
+
+ mLevel = 0;
+ mMatchNativePixmap = EGL_NONE;
+ mMaxPBufferWidth = texWidth;
+ mMaxPBufferHeight = texHeight;
+ mMaxPBufferPixels = texWidth*texHeight;
+ mMaxSwapInterval = maxInterval;
+ mMinSwapInterval = minInterval;
+ mNativeRenderable = EGL_FALSE;
+ mNativeVisualID = 0;
+ mNativeVisualType = 0;
+ mRenderableType = EGL_OPENGL_ES2_BIT;
+ mSampleBuffers = multiSample ? 1 : 0;
+ mSamples = multiSample;
+ mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+ mTransparentType = EGL_NONE;
+ mTransparentRedValue = 0;
+ mTransparentGreenValue = 0;
+ mTransparentBlueValue = 0;
+}
+
+EGLConfig Config::getHandle() const
+{
+ return (EGLConfig)(size_t)mConfigID;
+}
+
+SortConfig::SortConfig(const EGLint *attribList)
+ : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false)
+{
+ scanForWantedComponents(attribList);
+}
+
+void SortConfig::scanForWantedComponents(const EGLint *attribList)
+{
+ // [EGL] section 3.4.1 page 24
+ // Sorting rule #3: by larger total number of color bits, not considering
+ // components that are 0 or don't-care.
+ for (const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2)
+ {
+ if (attr[1] != 0 && attr[1] != EGL_DONT_CARE)
+ {
+ switch (attr[0])
+ {
+ case EGL_RED_SIZE: mWantRed = true; break;
+ case EGL_GREEN_SIZE: mWantGreen = true; break;
+ case EGL_BLUE_SIZE: mWantBlue = true; break;
+ case EGL_ALPHA_SIZE: mWantAlpha = true; break;
+ case EGL_LUMINANCE_SIZE: mWantLuminance = true; break;
+ }
+ }
+ }
+}
+
+EGLint SortConfig::wantedComponentsSize(const Config &config) const
+{
+ EGLint total = 0;
+
+ if (mWantRed) total += config.mRedSize;
+ if (mWantGreen) total += config.mGreenSize;
+ if (mWantBlue) total += config.mBlueSize;
+ if (mWantAlpha) total += config.mAlphaSize;
+ if (mWantLuminance) total += config.mLuminanceSize;
+
+ return total;
+}
+
+bool SortConfig::operator()(const Config *x, const Config *y) const
+{
+ return (*this)(*x, *y);
+}
+
+bool SortConfig::operator()(const Config &x, const Config &y) const
+{
+ #define SORT(attribute) \
+ if (x.attribute != y.attribute) \
+ { \
+ return x.attribute < y.attribute; \
+ }
+
+ META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG);
+ SORT(mConfigCaveat);
+
+ META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER);
+ SORT(mColorBufferType);
+
+ // By larger total number of color bits, only considering those that are requested to be > 0.
+ EGLint xComponentsSize = wantedComponentsSize(x);
+ EGLint yComponentsSize = wantedComponentsSize(y);
+ if (xComponentsSize != yComponentsSize)
+ {
+ return xComponentsSize > yComponentsSize;
+ }
+
+ SORT(mBufferSize);
+ SORT(mSampleBuffers);
+ SORT(mSamples);
+ SORT(mDepthSize);
+ SORT(mStencilSize);
+ SORT(mAlphaMaskSize);
+ SORT(mNativeVisualType);
+ SORT(mConfigID);
+
+ #undef SORT
+
+ return false;
+}
+
+// We'd like to use SortConfig to also eliminate duplicate configs.
+// This works as long as we never have two configs with different per-RGB-component layouts,
+// but the same total.
+// 5551 and 565 are different because R+G+B is different.
+// 5551 and 555 are different because bufferSize is different.
+const EGLint ConfigSet::mSortAttribs[] =
+{
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_LUMINANCE_SIZE, 1,
+ // BUT NOT ALPHA
+ EGL_NONE
+};
+
+ConfigSet::ConfigSet()
+ : mSet(SortConfig(mSortAttribs))
+{
+}
+
+void ConfigSet::add(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight)
+{
+ Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample, texWidth, texHeight);
+
+ mSet.insert(config);
+}
+
+size_t ConfigSet::size() const
+{
+ return mSet.size();
+}
+
+bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
+{
+ vector<const Config*> passed;
+ passed.reserve(mSet.size());
+
+ for (Iterator config = mSet.begin(); config != mSet.end(); config++)
+ {
+ bool match = true;
+ const EGLint *attribute = attribList;
+
+ while (attribute[0] != EGL_NONE)
+ {
+ switch (attribute[0])
+ {
+ case EGL_BUFFER_SIZE: match = config->mBufferSize >= attribute[1]; break;
+ case EGL_ALPHA_SIZE: match = config->mAlphaSize >= attribute[1]; break;
+ case EGL_BLUE_SIZE: match = config->mBlueSize >= attribute[1]; break;
+ case EGL_GREEN_SIZE: match = config->mGreenSize >= attribute[1]; break;
+ case EGL_RED_SIZE: match = config->mRedSize >= attribute[1]; break;
+ case EGL_DEPTH_SIZE: match = config->mDepthSize >= attribute[1]; break;
+ case EGL_STENCIL_SIZE: match = config->mStencilSize >= attribute[1]; break;
+ case EGL_CONFIG_CAVEAT: match = config->mConfigCaveat == attribute[1]; break;
+ case EGL_CONFIG_ID: match = config->mConfigID == attribute[1]; break;
+ case EGL_LEVEL: match = config->mLevel >= attribute[1]; break;
+ case EGL_NATIVE_RENDERABLE: match = config->mNativeRenderable == attribute[1]; break;
+ case EGL_NATIVE_VISUAL_TYPE: match = config->mNativeVisualType == attribute[1]; break;
+ case EGL_SAMPLES: match = config->mSamples >= attribute[1]; break;
+ case EGL_SAMPLE_BUFFERS: match = config->mSampleBuffers >= attribute[1]; break;
+ case EGL_SURFACE_TYPE: match = (config->mSurfaceType & attribute[1]) == attribute[1]; break;
+ case EGL_TRANSPARENT_TYPE: match = config->mTransparentType == attribute[1]; break;
+ case EGL_TRANSPARENT_BLUE_VALUE: match = config->mTransparentBlueValue == attribute[1]; break;
+ case EGL_TRANSPARENT_GREEN_VALUE: match = config->mTransparentGreenValue == attribute[1]; break;
+ case EGL_TRANSPARENT_RED_VALUE: match = config->mTransparentRedValue == attribute[1]; break;
+ case EGL_BIND_TO_TEXTURE_RGB: match = config->mBindToTextureRGB == attribute[1]; break;
+ case EGL_BIND_TO_TEXTURE_RGBA: match = config->mBindToTextureRGBA == attribute[1]; break;
+ case EGL_MIN_SWAP_INTERVAL: match = config->mMinSwapInterval == attribute[1]; break;
+ case EGL_MAX_SWAP_INTERVAL: match = config->mMaxSwapInterval == attribute[1]; break;
+ case EGL_LUMINANCE_SIZE: match = config->mLuminanceSize >= attribute[1]; break;
+ case EGL_ALPHA_MASK_SIZE: match = config->mAlphaMaskSize >= attribute[1]; break;
+ case EGL_COLOR_BUFFER_TYPE: match = config->mColorBufferType == attribute[1]; break;
+ case EGL_RENDERABLE_TYPE: match = (config->mRenderableType & attribute[1]) == attribute[1]; break;
+ case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break;
+ case EGL_CONFORMANT: match = (config->mConformant & attribute[1]) == attribute[1]; break;
+ case EGL_MAX_PBUFFER_WIDTH: match = config->mMaxPBufferWidth >= attribute[1]; break;
+ case EGL_MAX_PBUFFER_HEIGHT: match = config->mMaxPBufferHeight >= attribute[1]; break;
+ case EGL_MAX_PBUFFER_PIXELS: match = config->mMaxPBufferPixels >= attribute[1]; break;
+ default:
+ return false;
+ }
+
+ if (!match)
+ {
+ break;
+ }
+
+ attribute += 2;
+ }
+
+ if (match)
+ {
+ passed.push_back(&*config);
+ }
+ }
+
+ if (configs)
+ {
+ sort(passed.begin(), passed.end(), SortConfig(attribList));
+
+ EGLint index;
+ for (index = 0; index < configSize && index < static_cast<EGLint>(passed.size()); index++)
+ {
+ configs[index] = passed[index]->getHandle();
+ }
+
+ *numConfig = index;
+ }
+ else
+ {
+ *numConfig = passed.size();
+ }
+
+ return true;
+}
+
+const egl::Config *ConfigSet::get(EGLConfig configHandle)
+{
+ for (Iterator config = mSet.begin(); config != mSet.end(); config++)
+ {
+ if (config->getHandle() == configHandle)
+ {
+ return &(*config);
+ }
+ }
+
+ return NULL;
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Config.h b/Source/ThirdParty/ANGLE/src/libEGL/Config.h
new file mode 100644
index 000000000..95626ed1a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/Config.h
@@ -0,0 +1,118 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Config.h: Defines the egl::Config class, describing the format, type
+// and size for an egl::Surface. Implements EGLConfig and related functionality.
+// [EGL 1.4] section 3.4 page 15.
+
+#ifndef INCLUDE_CONFIG_H_
+#define INCLUDE_CONFIG_H_
+
+#define EGLAPI
+#include <EGL/egl.h>
+#include <d3d9.h>
+
+#include <set>
+
+#include "common/angleutils.h"
+
+namespace egl
+{
+class Display;
+
+class Config
+{
+ public:
+ Config(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight);
+
+ void setDefaults();
+ void set(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight);
+ EGLConfig getHandle() const;
+
+ const D3DDISPLAYMODE mDisplayMode;
+ const D3DFORMAT mRenderTargetFormat;
+ const D3DFORMAT mDepthStencilFormat;
+ const EGLint mMultiSample;
+
+ EGLint mBufferSize; // Depth of the color buffer
+ EGLint mRedSize; // Bits of Red in the color buffer
+ EGLint mGreenSize; // Bits of Green in the color buffer
+ EGLint mBlueSize; // Bits of Blue in the color buffer
+ EGLint mLuminanceSize; // Bits of Luminance in the color buffer
+ EGLint mAlphaSize; // Bits of Alpha in the color buffer
+ EGLint mAlphaMaskSize; // Bits of Alpha Mask in the mask buffer
+ EGLBoolean mBindToTextureRGB; // True if bindable to RGB textures.
+ EGLBoolean mBindToTextureRGBA; // True if bindable to RGBA textures.
+ EGLenum mColorBufferType; // Color buffer type
+ EGLenum mConfigCaveat; // Any caveats for the configuration
+ EGLint mConfigID; // Unique EGLConfig identifier
+ EGLint mConformant; // Whether contexts created with this config are conformant
+ EGLint mDepthSize; // Bits of Z in the depth buffer
+ EGLint mLevel; // Frame buffer level
+ EGLBoolean mMatchNativePixmap; // Match the native pixmap format
+ EGLint mMaxPBufferWidth; // Maximum width of pbuffer
+ EGLint mMaxPBufferHeight; // Maximum height of pbuffer
+ EGLint mMaxPBufferPixels; // Maximum size of pbuffer
+ EGLint mMaxSwapInterval; // Maximum swap interval
+ EGLint mMinSwapInterval; // Minimum swap interval
+ EGLBoolean mNativeRenderable; // EGL_TRUE if native rendering APIs can render to surface
+ EGLint mNativeVisualID; // Handle of corresponding native visual
+ EGLint mNativeVisualType; // Native visual type of the associated visual
+ EGLint mRenderableType; // Which client rendering APIs are supported.
+ EGLint mSampleBuffers; // Number of multisample buffers
+ EGLint mSamples; // Number of samples per pixel
+ EGLint mStencilSize; // Bits of Stencil in the stencil buffer
+ EGLint mSurfaceType; // Which types of EGL surfaces are supported.
+ EGLenum mTransparentType; // Type of transparency supported
+ EGLint mTransparentRedValue; // Transparent red value
+ EGLint mTransparentGreenValue; // Transparent green value
+ EGLint mTransparentBlueValue; // Transparent blue value
+};
+
+// Function object used by STL sorting routines for ordering Configs according to [EGL] section 3.4.1 page 24.
+class SortConfig
+{
+ public:
+ explicit SortConfig(const EGLint *attribList);
+
+ bool operator()(const Config *x, const Config *y) const;
+ bool operator()(const Config &x, const Config &y) const;
+
+ private:
+ void scanForWantedComponents(const EGLint *attribList);
+ EGLint wantedComponentsSize(const Config &config) const;
+
+ bool mWantRed;
+ bool mWantGreen;
+ bool mWantBlue;
+ bool mWantAlpha;
+ bool mWantLuminance;
+};
+
+class ConfigSet
+{
+ friend Display;
+
+ public:
+ ConfigSet();
+
+ void add(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample, EGLint texWidth, EGLint texHeight);
+ size_t size() const;
+ bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig);
+ const egl::Config *get(EGLConfig configHandle);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConfigSet);
+
+ typedef std::set<Config, SortConfig> Set;
+ typedef Set::iterator Iterator;
+ Set mSet;
+
+ static const EGLint mSortAttribs[];
+};
+}
+
+#endif // INCLUDE_CONFIG_H_
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Display.cpp b/Source/ThirdParty/ANGLE/src/libEGL/Display.cpp
new file mode 100644
index 000000000..1d64f9a10
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/Display.cpp
@@ -0,0 +1,897 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Display.cpp: Implements the egl::Display class, representing the abstract
+// display on which graphics are drawn. Implements EGLDisplay.
+// [EGL 1.4] section 2.1.2 page 3.
+
+#include "libEGL/Display.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "common/debug.h"
+#include "libGLESv2/mathutil.h"
+
+#include "libEGL/main.h"
+
+// Can also be enabled by defining FORCE_REF_RAST in the project's predefined macros
+#define REF_RAST 0
+
+// The "Debug This Pixel..." feature in PIX often fails when using the
+// D3D9Ex interfaces. In order to get debug pixel to work on a Vista/Win 7
+// machine, define "ANGLE_ENABLE_D3D9EX=0" in your project file.
+#if !defined(ANGLE_ENABLE_D3D9EX)
+// Enables use of the IDirect3D9Ex interface, when available
+#define ANGLE_ENABLE_D3D9EX 1
+#endif // !defined(ANGLE_ENABLE_D3D9EX)
+
+namespace egl
+{
+Display::Display(HDC deviceContext) : mDc(deviceContext)
+{
+ mD3d9Module = NULL;
+
+ mD3d9 = NULL;
+ mD3d9Ex = NULL;
+ mDevice = NULL;
+ mDeviceEx = NULL;
+ mDeviceWindow = NULL;
+
+ mAdapter = D3DADAPTER_DEFAULT;
+
+ #if REF_RAST == 1 || defined(FORCE_REF_RAST)
+ mDeviceType = D3DDEVTYPE_REF;
+ #else
+ mDeviceType = D3DDEVTYPE_HAL;
+ #endif
+
+ mMinSwapInterval = 1;
+ mMaxSwapInterval = 1;
+}
+
+Display::~Display()
+{
+ terminate();
+}
+
+bool Display::initialize()
+{
+ if (isInitialized())
+ {
+ return true;
+ }
+
+ mD3d9Module = GetModuleHandle(TEXT("d3d9.dll"));
+ if (mD3d9Module == NULL)
+ {
+ terminate();
+ return false;
+ }
+
+ typedef HRESULT (WINAPI *Direct3DCreate9ExFunc)(UINT, IDirect3D9Ex**);
+ Direct3DCreate9ExFunc Direct3DCreate9ExPtr = reinterpret_cast<Direct3DCreate9ExFunc>(GetProcAddress(mD3d9Module, "Direct3DCreate9Ex"));
+
+ // Use Direct3D9Ex if available. Among other things, this version is less
+ // inclined to report a lost context, for example when the user switches
+ // desktop. Direct3D9Ex is available in Windows Vista and later if suitable drivers are available.
+ if (ANGLE_ENABLE_D3D9EX && Direct3DCreate9ExPtr && SUCCEEDED(Direct3DCreate9ExPtr(D3D_SDK_VERSION, &mD3d9Ex)))
+ {
+ ASSERT(mD3d9Ex);
+ mD3d9Ex->QueryInterface(IID_IDirect3D9, reinterpret_cast<void**>(&mD3d9));
+ ASSERT(mD3d9);
+ }
+ else
+ {
+ mD3d9 = Direct3DCreate9(D3D_SDK_VERSION);
+ }
+
+ if (mD3d9)
+ {
+ if (mDc != NULL)
+ {
+ // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to
+ }
+
+ HRESULT result;
+
+ // Give up on getting device caps after about one second.
+ for (int i = 0; i < 10; ++i)
+ {
+ result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &mDeviceCaps);
+
+ if (SUCCEEDED(result))
+ {
+ break;
+ }
+ else if (result == D3DERR_NOTAVAILABLE)
+ {
+ Sleep(100); // Give the driver some time to initialize/recover
+ }
+ else if (FAILED(result)) // D3DERR_OUTOFVIDEOMEMORY, E_OUTOFMEMORY, D3DERR_INVALIDDEVICE, or another error we can't recover from
+ {
+ terminate();
+ return error(EGL_BAD_ALLOC, false);
+ }
+ }
+
+ if (mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(2, 0))
+ {
+ terminate();
+ return error(EGL_NOT_INITIALIZED, false);
+ }
+
+ // When DirectX9 is running with an older DirectX8 driver, a StretchRect from a regular texture to a render target texture is not supported.
+ // This is required by Texture2D::convertToRenderTarget.
+ if ((mDeviceCaps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) == 0)
+ {
+ terminate();
+ return error(EGL_NOT_INITIALIZED, false);
+ }
+
+ mMinSwapInterval = 4;
+ mMaxSwapInterval = 0;
+
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {mMinSwapInterval = std::min(mMinSwapInterval, 0); mMaxSwapInterval = std::max(mMaxSwapInterval, 0);}
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) {mMinSwapInterval = std::min(mMinSwapInterval, 1); mMaxSwapInterval = std::max(mMaxSwapInterval, 1);}
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) {mMinSwapInterval = std::min(mMinSwapInterval, 2); mMaxSwapInterval = std::max(mMaxSwapInterval, 2);}
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) {mMinSwapInterval = std::min(mMinSwapInterval, 3); mMaxSwapInterval = std::max(mMaxSwapInterval, 3);}
+ if (mDeviceCaps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) {mMinSwapInterval = std::min(mMinSwapInterval, 4); mMaxSwapInterval = std::max(mMaxSwapInterval, 4);}
+
+ mD3d9->GetAdapterIdentifier(mAdapter, 0, &mAdapterIdentifier);
+
+ const D3DFORMAT renderTargetFormats[] =
+ {
+ D3DFMT_A1R5G5B5,
+ // D3DFMT_A2R10G10B10, // The color_ramp conformance test uses ReadPixels with UNSIGNED_BYTE causing it to think that rendering skipped a colour value.
+ D3DFMT_A8R8G8B8,
+ D3DFMT_R5G6B5,
+ // D3DFMT_X1R5G5B5, // Has no compatible OpenGL ES renderbuffer format
+ D3DFMT_X8R8G8B8
+ };
+
+ const D3DFORMAT depthStencilFormats[] =
+ {
+ D3DFMT_UNKNOWN,
+ // D3DFMT_D16_LOCKABLE,
+ D3DFMT_D32,
+ // D3DFMT_D15S1,
+ D3DFMT_D24S8,
+ D3DFMT_D24X8,
+ // D3DFMT_D24X4S4,
+ D3DFMT_D16,
+ // D3DFMT_D32F_LOCKABLE,
+ // D3DFMT_D24FS8
+ };
+
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ ConfigSet configSet;
+
+ for (int formatIndex = 0; formatIndex < sizeof(renderTargetFormats) / sizeof(D3DFORMAT); formatIndex++)
+ {
+ D3DFORMAT renderTargetFormat = renderTargetFormats[formatIndex];
+
+ HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat);
+
+ if (SUCCEEDED(result))
+ {
+ for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++)
+ {
+ D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex];
+ HRESULT result = D3D_OK;
+
+ if(depthStencilFormat != D3DFMT_UNKNOWN)
+ {
+ result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat);
+ }
+
+ if (SUCCEEDED(result))
+ {
+ if(depthStencilFormat != D3DFMT_UNKNOWN)
+ {
+ result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat);
+ }
+
+ if (SUCCEEDED(result))
+ {
+ // FIXME: enumerate multi-sampling
+
+ configSet.add(currentDisplayMode, mMinSwapInterval, mMaxSwapInterval, renderTargetFormat, depthStencilFormat, 0,
+ mDeviceCaps.MaxTextureWidth, mDeviceCaps.MaxTextureHeight);
+ }
+ }
+ }
+ }
+ }
+
+ // Give the sorted configs a unique ID and store them internally
+ EGLint index = 1;
+ for (ConfigSet::Iterator config = configSet.mSet.begin(); config != configSet.mSet.end(); config++)
+ {
+ Config configuration = *config;
+ configuration.mConfigID = index;
+ index++;
+
+ mConfigSet.mSet.insert(configuration);
+ }
+ }
+
+ if (!isInitialized())
+ {
+ terminate();
+
+ return false;
+ }
+
+ initExtensionString();
+
+ static const TCHAR windowName[] = TEXT("AngleHiddenWindow");
+ static const TCHAR className[] = TEXT("STATIC");
+
+ mDeviceWindow = CreateWindowEx(WS_EX_NOACTIVATE, className, windowName, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, HWND_MESSAGE, NULL, GetModuleHandle(NULL), NULL);
+
+ return true;
+}
+
+void Display::terminate()
+{
+ while (!mSurfaceSet.empty())
+ {
+ destroySurface(*mSurfaceSet.begin());
+ }
+
+ while (!mContextSet.empty())
+ {
+ destroyContext(*mContextSet.begin());
+ }
+
+ if (mDevice)
+ {
+ // If the device is lost, reset it first to prevent leaving the driver in an unstable state
+ if (isDeviceLost())
+ {
+ resetDevice();
+ }
+
+ mDevice->Release();
+ mDevice = NULL;
+ }
+
+ if (mDeviceEx)
+ {
+ mDeviceEx->Release();
+ mDeviceEx = NULL;
+ }
+
+ if (mD3d9)
+ {
+ mD3d9->Release();
+ mD3d9 = NULL;
+ }
+
+ if (mDeviceWindow)
+ {
+ DestroyWindow(mDeviceWindow);
+ mDeviceWindow = NULL;
+ }
+
+ if (mD3d9Ex)
+ {
+ mD3d9Ex->Release();
+ mD3d9Ex = NULL;
+ }
+
+ if (mD3d9Module)
+ {
+ mD3d9Module = NULL;
+ }
+}
+
+void Display::startScene()
+{
+ if (!mSceneStarted)
+ {
+ long result = mDevice->BeginScene();
+ ASSERT(SUCCEEDED(result));
+ mSceneStarted = true;
+ }
+}
+
+void Display::endScene()
+{
+ if (mSceneStarted)
+ {
+ long result = mDevice->EndScene();
+ ASSERT(SUCCEEDED(result));
+ mSceneStarted = false;
+ }
+}
+
+bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig)
+{
+ return mConfigSet.getConfigs(configs, attribList, configSize, numConfig);
+}
+
+bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value)
+{
+ const egl::Config *configuration = mConfigSet.get(config);
+
+ switch (attribute)
+ {
+ case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break;
+ case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break;
+ case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break;
+ case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break;
+ case EGL_RED_SIZE: *value = configuration->mRedSize; break;
+ case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break;
+ case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break;
+ case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break;
+ case EGL_CONFIG_ID: *value = configuration->mConfigID; break;
+ case EGL_LEVEL: *value = configuration->mLevel; break;
+ case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break;
+ case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break;
+ case EGL_SAMPLES: *value = configuration->mSamples; break;
+ case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break;
+ case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break;
+ case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break;
+ case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break;
+ case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break;
+ case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break;
+ case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break;
+ case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break;
+ case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break;
+ case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break;
+ case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break;
+ case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break;
+ case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break;
+ case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break;
+ case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break;
+ case EGL_CONFORMANT: *value = configuration->mConformant; break;
+ case EGL_MAX_PBUFFER_WIDTH: *value = configuration->mMaxPBufferWidth; break;
+ case EGL_MAX_PBUFFER_HEIGHT: *value = configuration->mMaxPBufferHeight; break;
+ case EGL_MAX_PBUFFER_PIXELS: *value = configuration->mMaxPBufferPixels; break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool Display::createDevice()
+{
+ D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
+ DWORD behaviorFlags = D3DCREATE_FPU_PRESERVE | D3DCREATE_NOWINDOWCHANGES;
+
+ HRESULT result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE, &presentParameters, &mDevice);
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DEVICELOST)
+ {
+ return error(EGL_BAD_ALLOC, false);
+ }
+
+ if (FAILED(result))
+ {
+ result = mD3d9->CreateDevice(mAdapter, mDeviceType, mDeviceWindow, behaviorFlags | D3DCREATE_SOFTWARE_VERTEXPROCESSING, &presentParameters, &mDevice);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_NOTAVAILABLE || result == D3DERR_DEVICELOST);
+ return error(EGL_BAD_ALLOC, false);
+ }
+ }
+
+ if (mD3d9Ex)
+ {
+ result = mDevice->QueryInterface(IID_IDirect3DDevice9Ex, (void**) &mDeviceEx);
+ ASSERT(SUCCEEDED(result));
+ }
+
+ // Permanent non-default states
+ mDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
+
+ mSceneStarted = false;
+
+ return true;
+}
+
+bool Display::resetDevice()
+{
+ D3DPRESENT_PARAMETERS presentParameters = getDefaultPresentParameters();
+ HRESULT result;
+
+ do
+ {
+ Sleep(0); // Give the graphics driver some CPU time
+
+ result = mDevice->Reset(&presentParameters);
+ }
+ while (result == D3DERR_DEVICELOST);
+
+ if (FAILED(result))
+ {
+ return error(EGL_BAD_ALLOC, false);
+ }
+
+ ASSERT(SUCCEEDED(result));
+
+ return true;
+}
+
+EGLSurface Display::createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList)
+{
+ const Config *configuration = mConfigSet.get(config);
+
+ if (attribList)
+ {
+ while (*attribList != EGL_NONE)
+ {
+ switch (attribList[0])
+ {
+ case EGL_RENDER_BUFFER:
+ switch (attribList[1])
+ {
+ case EGL_BACK_BUFFER:
+ break;
+ case EGL_SINGLE_BUFFER:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ break;
+ case EGL_VG_COLORSPACE:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ case EGL_VG_ALPHA_FORMAT:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ attribList += 2;
+ }
+ }
+
+ if (hasExistingWindowSurface(window))
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+
+ Surface *surface = new Surface(this, configuration, window);
+
+ if (!surface->initialize())
+ {
+ delete surface;
+ return EGL_NO_SURFACE;
+ }
+
+ mSurfaceSet.insert(surface);
+
+ return success(surface);
+}
+
+EGLSurface Display::createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList)
+{
+ EGLint width = 0, height = 0;
+ EGLenum textureFormat = EGL_NO_TEXTURE;
+ EGLenum textureTarget = EGL_NO_TEXTURE;
+ const Config *configuration = mConfigSet.get(config);
+
+ if (attribList)
+ {
+ while (*attribList != EGL_NONE)
+ {
+ switch (attribList[0])
+ {
+ case EGL_WIDTH:
+ width = attribList[1];
+ break;
+ case EGL_HEIGHT:
+ height = attribList[1];
+ break;
+ case EGL_LARGEST_PBUFFER:
+ if (attribList[1] != EGL_FALSE)
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_TEXTURE_FORMAT:
+ switch (attribList[1])
+ {
+ case EGL_NO_TEXTURE:
+ case EGL_TEXTURE_RGB:
+ case EGL_TEXTURE_RGBA:
+ textureFormat = attribList[1];
+ break;
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ break;
+ case EGL_TEXTURE_TARGET:
+ switch (attribList[1])
+ {
+ case EGL_NO_TEXTURE:
+ case EGL_TEXTURE_2D:
+ textureTarget = attribList[1];
+ break;
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+ break;
+ case EGL_MIPMAP_TEXTURE:
+ if (attribList[1] != EGL_FALSE)
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ break;
+ case EGL_VG_COLORSPACE:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ case EGL_VG_ALPHA_FORMAT:
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ attribList += 2;
+ }
+ }
+
+ if (width < 0 || height < 0)
+ {
+ return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+
+ if (width == 0 || height == 0)
+ {
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ if (textureFormat != EGL_NO_TEXTURE && !getNonPower2TextureSupport() && (!gl::isPow2(width) || !gl::isPow2(height)))
+ {
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ if ((textureFormat != EGL_NO_TEXTURE && textureTarget == EGL_NO_TEXTURE) ||
+ (textureFormat == EGL_NO_TEXTURE && textureTarget != EGL_NO_TEXTURE))
+ {
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ if (!(configuration->mSurfaceType & EGL_PBUFFER_BIT))
+ {
+ return error(EGL_BAD_MATCH, EGL_NO_SURFACE);
+ }
+
+ if ((textureFormat == EGL_TEXTURE_RGB && configuration->mBindToTextureRGB != EGL_TRUE) ||
+ (textureFormat == EGL_TEXTURE_RGBA && configuration->mBindToTextureRGBA != EGL_TRUE))
+ {
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
+ }
+
+ Surface *surface = new Surface(this, configuration, shareHandle, width, height, textureFormat, textureTarget);
+
+ if (!surface->initialize())
+ {
+ delete surface;
+ return EGL_NO_SURFACE;
+ }
+
+ mSurfaceSet.insert(surface);
+
+ return success(surface);
+}
+
+EGLContext Display::createContext(EGLConfig configHandle, const gl::Context *shareContext)
+{
+ if (!mDevice)
+ {
+ if (!createDevice())
+ {
+ return NULL;
+ }
+ }
+ else if (isDeviceLost()) // Lost device
+ {
+ // Release surface resources to make the Reset() succeed
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ (*surface)->release();
+ }
+
+ if (!resetDevice())
+ {
+ return NULL;
+ }
+
+ // Restore any surfaces that may have been lost
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ (*surface)->resetSwapChain();
+ }
+ }
+
+ const egl::Config *config = mConfigSet.get(configHandle);
+
+ gl::Context *context = glCreateContext(config, shareContext);
+ mContextSet.insert(context);
+
+ return context;
+}
+
+void Display::destroySurface(egl::Surface *surface)
+{
+ delete surface;
+ mSurfaceSet.erase(surface);
+}
+
+void Display::destroyContext(gl::Context *context)
+{
+ glDestroyContext(context);
+ mContextSet.erase(context);
+}
+
+bool Display::isInitialized() const
+{
+ return mD3d9 != NULL && mConfigSet.size() > 0;
+}
+
+bool Display::isValidConfig(EGLConfig config)
+{
+ return mConfigSet.get(config) != NULL;
+}
+
+bool Display::isValidContext(gl::Context *context)
+{
+ return mContextSet.find(context) != mContextSet.end();
+}
+
+bool Display::isValidSurface(egl::Surface *surface)
+{
+ return mSurfaceSet.find(surface) != mSurfaceSet.end();
+}
+
+bool Display::hasExistingWindowSurface(HWND window)
+{
+ for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++)
+ {
+ if ((*surface)->getWindowHandle() == window)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+EGLint Display::getMinSwapInterval()
+{
+ return mMinSwapInterval;
+}
+
+EGLint Display::getMaxSwapInterval()
+{
+ return mMaxSwapInterval;
+}
+
+IDirect3DDevice9 *Display::getDevice()
+{
+ if (!mDevice)
+ {
+ if (!createDevice())
+ {
+ return NULL;
+ }
+ }
+
+ return mDevice;
+}
+
+D3DCAPS9 Display::getDeviceCaps()
+{
+ return mDeviceCaps;
+}
+
+D3DADAPTER_IDENTIFIER9 *Display::getAdapterIdentifier()
+{
+ return &mAdapterIdentifier;
+}
+
+bool Display::isDeviceLost()
+{
+ if (mDeviceEx)
+ {
+ return FAILED(mDeviceEx->CheckDeviceState(NULL));
+ }
+ else
+ {
+ return FAILED(mDevice->TestCooperativeLevel());
+ }
+}
+
+void Display::getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray)
+{
+ for (int multiSampleIndex = 0; multiSampleIndex <= D3DMULTISAMPLE_16_SAMPLES; multiSampleIndex++)
+ {
+ HRESULT result = mD3d9->CheckDeviceMultiSampleType(mAdapter, mDeviceType, format,
+ TRUE, (D3DMULTISAMPLE_TYPE)multiSampleIndex, NULL);
+
+ multiSampleArray[multiSampleIndex] = SUCCEEDED(result);
+ }
+}
+
+bool Display::getCompressedTextureSupport()
+{
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_DXT1));
+}
+
+bool Display::getFloatTextureSupport(bool *filtering, bool *renderable)
+{
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
+
+ *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F))&&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
+
+ if (!filtering && !renderable)
+ {
+ return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
+ D3DRTYPE_TEXTURE, D3DFMT_A32B32G32R32F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A32B32G32R32F));
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool Display::getHalfFloatTextureSupport(bool *filtering, bool *renderable)
+{
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ *filtering = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_FILTER,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
+
+ *renderable = SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
+
+ if (!filtering && !renderable)
+ {
+ return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
+ D3DRTYPE_TEXTURE, D3DFMT_A16B16G16R16F)) &&
+ SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0,
+ D3DRTYPE_CUBETEXTURE, D3DFMT_A16B16G16R16F));
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool Display::getLuminanceTextureSupport()
+{
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_L8));
+}
+
+bool Display::getLuminanceAlphaTextureSupport()
+{
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ return SUCCEEDED(mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, 0, D3DRTYPE_TEXTURE, D3DFMT_A8L8));
+}
+
+D3DPOOL Display::getBufferPool(DWORD usage) const
+{
+ if (mD3d9Ex != NULL)
+ {
+ return D3DPOOL_DEFAULT;
+ }
+ else
+ {
+ if (!(usage & D3DUSAGE_DYNAMIC))
+ {
+ return D3DPOOL_MANAGED;
+ }
+ }
+
+ return D3DPOOL_DEFAULT;
+}
+
+bool Display::getEventQuerySupport()
+{
+ IDirect3DQuery9 *query;
+ HRESULT result = mDevice->CreateQuery(D3DQUERYTYPE_EVENT, &query);
+ if (SUCCEEDED(result))
+ {
+ query->Release();
+ }
+
+ return result != D3DERR_NOTAVAILABLE;
+}
+
+D3DPRESENT_PARAMETERS Display::getDefaultPresentParameters()
+{
+ D3DPRESENT_PARAMETERS presentParameters = {0};
+
+ // The default swap chain is never actually used. Surface will create a new swap chain with the proper parameters.
+ presentParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
+ presentParameters.BackBufferCount = 1;
+ presentParameters.BackBufferFormat = D3DFMT_UNKNOWN;
+ presentParameters.BackBufferWidth = 1;
+ presentParameters.BackBufferHeight = 1;
+ presentParameters.EnableAutoDepthStencil = FALSE;
+ presentParameters.Flags = 0;
+ presentParameters.hDeviceWindow = mDeviceWindow;
+ presentParameters.MultiSampleQuality = 0;
+ presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
+ presentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
+ presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ presentParameters.Windowed = TRUE;
+
+ return presentParameters;
+}
+
+void Display::initExtensionString()
+{
+ mExtensionString += "EGL_ANGLE_query_surface_pointer ";
+
+ if (isD3d9ExDevice()) {
+ mExtensionString += "EGL_ANGLE_surface_d3d_texture_2d_share_handle ";
+ mExtensionString += "EGL_ANGLE_d3d_share_handle_client_buffer ";
+ }
+
+ std::string::size_type end = mExtensionString.find_last_not_of(' ');
+ if (end != std::string::npos)
+ {
+ mExtensionString.resize(end+1);
+ }
+}
+
+const char *Display::getExtensionString() const
+{
+ return mExtensionString.c_str();
+}
+
+// Only Direct3D 10 ready devices support all the necessary vertex texture formats.
+// We test this using D3D9 by checking support for the R16F format.
+bool Display::getVertexTextureSupport() const
+{
+ if (!isInitialized() || mDeviceCaps.PixelShaderVersion < D3DPS_VERSION(3, 0))
+ {
+ return false;
+ }
+
+ D3DDISPLAYMODE currentDisplayMode;
+ mD3d9->GetAdapterDisplayMode(mAdapter, &currentDisplayMode);
+
+ HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F);
+
+ return SUCCEEDED(result);
+}
+
+bool Display::getNonPower2TextureSupport() const
+{
+ return !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_POW2) &&
+ !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) &&
+ !(mDeviceCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL);
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Display.h b/Source/ThirdParty/ANGLE/src/libEGL/Display.h
new file mode 100644
index 000000000..86de5cd4b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/Display.h
@@ -0,0 +1,118 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Display.h: Defines the egl::Display class, representing the abstract
+// display on which graphics are drawn. Implements EGLDisplay.
+// [EGL 1.4] section 2.1.2 page 3.
+
+#ifndef INCLUDE_DISPLAY_H_
+#define INCLUDE_DISPLAY_H_
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <d3d9.h>
+
+#include <set>
+
+#include "libGLESv2/Context.h"
+
+#include "libEGL/Config.h"
+#include "libEGL/Surface.h"
+
+namespace egl
+{
+class Display
+{
+ public:
+ Display(HDC deviceContext);
+
+ ~Display();
+
+ bool initialize();
+ void terminate();
+
+ virtual void startScene();
+ virtual void endScene();
+
+ bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig);
+ bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value);
+
+ EGLSurface createWindowSurface(HWND window, EGLConfig config, const EGLint *attribList);
+ EGLSurface createOffscreenSurface(EGLConfig config, HANDLE shareHandle, const EGLint *attribList);
+ EGLContext createContext(EGLConfig configHandle, const gl::Context *shareContext);
+
+ void destroySurface(egl::Surface *surface);
+ void destroyContext(gl::Context *context);
+
+ bool isInitialized() const;
+ bool isValidConfig(EGLConfig config);
+ bool isValidContext(gl::Context *context);
+ bool isValidSurface(egl::Surface *surface);
+ bool hasExistingWindowSurface(HWND window);
+
+ EGLint getMinSwapInterval();
+ EGLint getMaxSwapInterval();
+
+ virtual IDirect3DDevice9 *getDevice();
+ virtual D3DCAPS9 getDeviceCaps();
+ virtual D3DADAPTER_IDENTIFIER9 *getAdapterIdentifier();
+ bool isDeviceLost();
+ virtual void getMultiSampleSupport(D3DFORMAT format, bool *multiSampleArray);
+ virtual bool getCompressedTextureSupport();
+ virtual bool getEventQuerySupport();
+ virtual bool getFloatTextureSupport(bool *filtering, bool *renderable);
+ virtual bool getHalfFloatTextureSupport(bool *filtering, bool *renderable);
+ virtual bool getLuminanceTextureSupport();
+ virtual bool getLuminanceAlphaTextureSupport();
+ virtual bool getVertexTextureSupport() const;
+ virtual bool getNonPower2TextureSupport() const;
+ virtual D3DPOOL getBufferPool(DWORD usage) const;
+
+ bool isD3d9ExDevice() { return mD3d9Ex != NULL; }
+ const char *getExtensionString() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Display);
+
+ D3DPRESENT_PARAMETERS getDefaultPresentParameters();
+
+ const HDC mDc;
+
+ HMODULE mD3d9Module;
+
+ UINT mAdapter;
+ D3DDEVTYPE mDeviceType;
+ IDirect3D9 *mD3d9; // Always valid after successful initialization.
+ IDirect3D9Ex *mD3d9Ex; // Might be null if D3D9Ex is not supported.
+ IDirect3DDevice9 *mDevice;
+ IDirect3DDevice9Ex *mDeviceEx; // Might be null if D3D9Ex is not supported.
+ D3DCAPS9 mDeviceCaps;
+ D3DADAPTER_IDENTIFIER9 mAdapterIdentifier;
+ HWND mDeviceWindow;
+
+ bool mSceneStarted;
+ EGLint mMaxSwapInterval;
+ EGLint mMinSwapInterval;
+
+ typedef std::set<Surface*> SurfaceSet;
+ SurfaceSet mSurfaceSet;
+
+ ConfigSet mConfigSet;
+
+ typedef std::set<gl::Context*> ContextSet;
+ ContextSet mContextSet;
+
+ bool createDevice();
+ bool resetDevice();
+
+ void initExtensionString();
+ std::string mExtensionString;
+};
+}
+
+#endif // INCLUDE_DISPLAY_H_
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp b/Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp
new file mode 100644
index 000000000..eafe5e2d3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/Surface.cpp
@@ -0,0 +1,495 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Surface.cpp: Implements the egl::Surface class, representing a drawing surface
+// such as the client area of a window, including any back buffers.
+// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3.
+
+#include <tchar.h>
+
+#include "libEGL/Surface.h"
+
+#include "common/debug.h"
+#include "libGLESv2/Texture.h"
+
+#include "libEGL/main.h"
+#include "libEGL/Display.h"
+
+#include <dwmapi.h>
+
+namespace egl
+{
+
+namespace
+{
+const int versionWindowsVista = MAKEWORD(0x00, 0x06);
+const int versionWindows7 = MAKEWORD(0x01, 0x06);
+
+// Return the version of the operating system in a format suitable for ordering
+// comparison.
+int getComparableOSVersion()
+{
+ DWORD version = GetVersion();
+ int majorVersion = LOBYTE(LOWORD(version));
+ int minorVersion = HIBYTE(LOWORD(version));
+ return MAKEWORD(minorVersion, majorVersion);
+}
+}
+
+Surface::Surface(Display *display, const Config *config, HWND window)
+ : mDisplay(display), mConfig(config), mWindow(window)
+{
+ mSwapChain = NULL;
+ mDepthStencil = NULL;
+ mRenderTarget = NULL;
+ mOffscreenTexture = NULL;
+ mShareHandle = NULL;
+ mTexture = NULL;
+ mTextureFormat = EGL_NO_TEXTURE;
+ mTextureTarget = EGL_NO_TEXTURE;
+
+ mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
+ mRenderBuffer = EGL_BACK_BUFFER;
+ mSwapBehavior = EGL_BUFFER_PRESERVED;
+ mSwapInterval = -1;
+ setSwapInterval(1);
+
+ subclassWindow();
+}
+
+Surface::Surface(Display *display, const Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureType)
+ : mDisplay(display), mWindow(NULL), mConfig(config), mShareHandle(shareHandle), mWidth(width), mHeight(height)
+{
+ mSwapChain = NULL;
+ mDepthStencil = NULL;
+ mRenderTarget = NULL;
+ mOffscreenTexture = NULL;
+ mWindowSubclassed = false;
+ mTexture = NULL;
+ mTextureFormat = textureFormat;
+ mTextureTarget = textureType;
+
+ mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio
+ mRenderBuffer = EGL_BACK_BUFFER;
+ mSwapBehavior = EGL_BUFFER_PRESERVED;
+ mSwapInterval = -1;
+ setSwapInterval(1);
+}
+
+Surface::~Surface()
+{
+ unsubclassWindow();
+ release();
+}
+
+bool Surface::initialize()
+{
+ ASSERT(!mSwapChain && !mOffscreenTexture && !mDepthStencil);
+
+ if (!resetSwapChain())
+ return false;
+
+ // Modify present parameters for this window, if we are composited,
+ // to minimize the amount of queuing done by DWM between our calls to
+ // present and the actual screen.
+ if (mWindow && (getComparableOSVersion() >= versionWindowsVista)) {
+ BOOL isComposited;
+ HRESULT result = DwmIsCompositionEnabled(&isComposited);
+ if (SUCCEEDED(result) && isComposited) {
+ DWM_PRESENT_PARAMETERS presentParams;
+ memset(&presentParams, 0, sizeof(presentParams));
+ presentParams.cbSize = sizeof(DWM_PRESENT_PARAMETERS);
+ presentParams.cBuffer = 2;
+
+ result = DwmSetPresentParameters(mWindow, &presentParams);
+ if (FAILED(result))
+ ERR("Unable to set present parameters: %081X", result);
+ }
+ }
+
+ return true;
+}
+
+void Surface::release()
+{
+ if (mSwapChain)
+ {
+ mSwapChain->Release();
+ mSwapChain = NULL;
+ }
+
+ if (mDepthStencil)
+ {
+ mDepthStencil->Release();
+ mDepthStencil = NULL;
+ }
+
+ if (mRenderTarget)
+ {
+ mRenderTarget->Release();
+ mRenderTarget = NULL;
+ }
+
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->Release();
+ mOffscreenTexture = NULL;
+ }
+
+ if (mTexture)
+ {
+ mTexture->releaseTexImage();
+ mTexture = NULL;
+ }
+}
+
+bool Surface::resetSwapChain()
+{
+ if (!mWindow)
+ {
+ return resetSwapChain(mWidth, mHeight);
+ }
+
+ RECT windowRect;
+ if (!GetClientRect(getWindowHandle(), &windowRect))
+ {
+ ASSERT(false);
+
+ ERR("Could not retrieve the window dimensions");
+ return false;
+ }
+
+ return resetSwapChain(windowRect.right - windowRect.left, windowRect.bottom - windowRect.top);
+}
+
+bool Surface::resetSwapChain(int backbufferWidth, int backbufferHeight)
+{
+ IDirect3DDevice9 *device = mDisplay->getDevice();
+
+ if (device == NULL)
+ {
+ return false;
+ }
+
+ // Evict all non-render target textures to system memory and release all resources
+ // before reallocating them to free up as much video memory as possible.
+ device->EvictManagedResources();
+ release();
+
+ D3DPRESENT_PARAMETERS presentParameters = {0};
+ HRESULT result;
+
+ bool useFlipEx = (getComparableOSVersion() >= versionWindows7) && mDisplay->isD3d9ExDevice();
+
+ // FlipEx causes unseemly stretching when resizing windows AND when one
+ // draws outside of the WM_PAINT callback. While this is seldom a problem in
+ // single process applications, it is particuarly noticeable in multiprocess
+ // applications. Therefore, if the creator process of our window is not in
+ // the current process, disable use of FlipEx.
+ DWORD windowPID;
+ GetWindowThreadProcessId(mWindow, &windowPID);
+ if(windowPID != GetCurrentProcessId())
+ useFlipEx = false;
+
+ presentParameters.AutoDepthStencilFormat = mConfig->mDepthStencilFormat;
+ // We set BackBufferCount = 1 even when we use D3DSWAPEFFECT_FLIPEX.
+ // We do this because DirectX docs are a bit vague whether to set this to 1
+ // or 2. The runtime seems to accept 1, so we speculate that either it is
+ // forcing it to 2 without telling us, or better, doing something smart
+ // behind the scenes knowing that we don't need more.
+ presentParameters.BackBufferCount = 1;
+ presentParameters.BackBufferFormat = mConfig->mRenderTargetFormat;
+ presentParameters.EnableAutoDepthStencil = FALSE;
+ presentParameters.Flags = 0;
+ presentParameters.hDeviceWindow = getWindowHandle();
+ presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented
+ presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented
+ presentParameters.PresentationInterval = mPresentInterval;
+ // Use flipEx on Win7 or greater.
+ if(useFlipEx)
+ presentParameters.SwapEffect = D3DSWAPEFFECT_FLIPEX;
+ else
+ presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+ presentParameters.Windowed = TRUE;
+ presentParameters.BackBufferWidth = backbufferWidth;
+ presentParameters.BackBufferHeight = backbufferHeight;
+
+ if (mWindow)
+ {
+ result = device->CreateAdditionalSwapChain(&presentParameters, &mSwapChain);
+ } else {
+ HANDLE *pShareHandle = NULL;
+ if (mDisplay->isD3d9ExDevice()) {
+ pShareHandle = &mShareHandle;
+ }
+
+ result = device->CreateTexture(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight, 1, D3DUSAGE_RENDERTARGET,
+ presentParameters.BackBufferFormat, D3DPOOL_DEFAULT, &mOffscreenTexture, pShareHandle);
+ }
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ ERR("Could not create additional swap chains or offscreen surfaces: %08lX", result);
+ release();
+ return error(EGL_BAD_ALLOC, false);
+ }
+
+ if (mConfig->mDepthStencilFormat != D3DFMT_UNKNOWN)
+ {
+ result = device->CreateDepthStencilSurface(presentParameters.BackBufferWidth, presentParameters.BackBufferHeight,
+ presentParameters.AutoDepthStencilFormat, presentParameters.MultiSampleType,
+ presentParameters.MultiSampleQuality, FALSE, &mDepthStencil, NULL);
+ }
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ ERR("Could not create depthstencil surface for new swap chain: %08lX", result);
+ release();
+ return error(EGL_BAD_ALLOC, false);
+ }
+
+ if (mWindow) {
+ mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mRenderTarget);
+ InvalidateRect(mWindow, NULL, FALSE);
+ } else {
+ mOffscreenTexture->GetSurfaceLevel(0, &mRenderTarget);
+ }
+
+ mWidth = presentParameters.BackBufferWidth;
+ mHeight = presentParameters.BackBufferHeight;
+
+ mPresentIntervalDirty = false;
+ return true;
+}
+
+HWND Surface::getWindowHandle()
+{
+ return mWindow;
+}
+
+
+#define kSurfaceProperty _TEXT("Egl::SurfaceOwner")
+#define kParentWndProc _TEXT("Egl::SurfaceParentWndProc")
+
+static LRESULT CALLBACK SurfaceWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
+{
+ if (message == WM_SIZE)
+ {
+ Surface* surf = reinterpret_cast<Surface*>(GetProp(hwnd, kSurfaceProperty));
+ if(surf)
+ {
+ surf->checkForOutOfDateSwapChain();
+ }
+ }
+ WNDPROC prevWndFunc = reinterpret_cast<WNDPROC >(GetProp(hwnd, kParentWndProc));
+ return CallWindowProc(prevWndFunc, hwnd, message, wparam, lparam);
+}
+
+void Surface::subclassWindow()
+{
+ if (!mWindow)
+ {
+ return;
+ }
+
+ DWORD processId;
+ DWORD threadId = GetWindowThreadProcessId(mWindow, &processId);
+ if (processId != GetCurrentProcessId() || threadId != GetCurrentThreadId())
+ {
+ return;
+ }
+
+ SetLastError(0);
+ LONG oldWndProc = SetWindowLong(mWindow, GWL_WNDPROC, reinterpret_cast<LONG>(SurfaceWindowProc));
+ if(oldWndProc == 0 && GetLastError() != ERROR_SUCCESS)
+ {
+ mWindowSubclassed = false;
+ return;
+ }
+
+ SetProp(mWindow, kSurfaceProperty, reinterpret_cast<HANDLE>(this));
+ SetProp(mWindow, kParentWndProc, reinterpret_cast<HANDLE>(oldWndProc));
+ mWindowSubclassed = true;
+}
+
+void Surface::unsubclassWindow()
+{
+ if(!mWindowSubclassed)
+ {
+ return;
+ }
+
+ // un-subclass
+ LONG parentWndFunc = reinterpret_cast<LONG>(GetProp(mWindow, kParentWndProc));
+
+ // Check the windowproc is still SurfaceWindowProc.
+ // If this assert fails, then it is likely the application has subclassed the
+ // hwnd as well and did not unsubclass before destroying its EGL context. The
+ // application should be modified to either subclass before initializing the
+ // EGL context, or to unsubclass before destroying the EGL context.
+ if(parentWndFunc)
+ {
+ LONG prevWndFunc = SetWindowLong(mWindow, GWL_WNDPROC, parentWndFunc);
+ ASSERT(prevWndFunc == reinterpret_cast<LONG>(SurfaceWindowProc));
+ }
+
+ RemoveProp(mWindow, kSurfaceProperty);
+ RemoveProp(mWindow, kParentWndProc);
+ mWindowSubclassed = false;
+}
+
+bool Surface::checkForOutOfDateSwapChain()
+{
+ RECT client;
+ if (!GetClientRect(getWindowHandle(), &client))
+ {
+ ASSERT(false);
+ return false;
+ }
+
+ // Grow the buffer now, if the window has grown. We need to grow now to avoid losing information.
+ int clientWidth = client.right - client.left;
+ int clientHeight = client.bottom - client.top;
+ bool sizeDirty = clientWidth != getWidth() || clientHeight != getHeight();
+
+ if (sizeDirty || mPresentIntervalDirty)
+ {
+ resetSwapChain(clientWidth, clientHeight);
+ if (static_cast<egl::Surface*>(getCurrentDrawSurface()) == this)
+ {
+ glMakeCurrent(glGetCurrentContext(), static_cast<egl::Display*>(getCurrentDisplay()), this);
+ }
+
+ return true;
+ }
+ return false;
+}
+
+DWORD Surface::convertInterval(EGLint interval)
+{
+ switch(interval)
+ {
+ case 0: return D3DPRESENT_INTERVAL_IMMEDIATE;
+ case 1: return D3DPRESENT_INTERVAL_ONE;
+ case 2: return D3DPRESENT_INTERVAL_TWO;
+ case 3: return D3DPRESENT_INTERVAL_THREE;
+ case 4: return D3DPRESENT_INTERVAL_FOUR;
+ default: UNREACHABLE();
+ }
+
+ return D3DPRESENT_INTERVAL_DEFAULT;
+}
+
+bool Surface::swap()
+{
+ if (mSwapChain)
+ {
+ mDisplay->endScene();
+
+ HRESULT result = mSwapChain->Present(NULL, NULL, NULL, NULL, 0);
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR)
+ {
+ return error(EGL_BAD_ALLOC, false);
+ }
+
+ if (result == D3DERR_DEVICELOST || result == D3DERR_DEVICEHUNG || result == D3DERR_DEVICEREMOVED)
+ {
+ return error(EGL_CONTEXT_LOST, false);
+ }
+
+ ASSERT(SUCCEEDED(result));
+
+ checkForOutOfDateSwapChain();
+ }
+
+ return true;
+}
+
+EGLint Surface::getWidth() const
+{
+ return mWidth;
+}
+
+EGLint Surface::getHeight() const
+{
+ return mHeight;
+}
+
+IDirect3DSurface9 *Surface::getRenderTarget()
+{
+ if (mRenderTarget)
+ {
+ mRenderTarget->AddRef();
+ }
+
+ return mRenderTarget;
+}
+
+IDirect3DSurface9 *Surface::getDepthStencil()
+{
+ if (mDepthStencil)
+ {
+ mDepthStencil->AddRef();
+ }
+
+ return mDepthStencil;
+}
+
+IDirect3DTexture9 *Surface::getOffscreenTexture()
+{
+ if (mOffscreenTexture)
+ {
+ mOffscreenTexture->AddRef();
+ }
+
+ return mOffscreenTexture;
+}
+
+void Surface::setSwapInterval(EGLint interval)
+{
+ if (mSwapInterval == interval)
+ {
+ return;
+ }
+
+ mSwapInterval = interval;
+ mSwapInterval = std::max(mSwapInterval, mDisplay->getMinSwapInterval());
+ mSwapInterval = std::min(mSwapInterval, mDisplay->getMaxSwapInterval());
+
+ mPresentInterval = convertInterval(mSwapInterval);
+ mPresentIntervalDirty = true;
+}
+
+EGLenum Surface::getTextureFormat() const
+{
+ return mTextureFormat;
+}
+
+EGLenum Surface::getTextureTarget() const
+{
+ return mTextureTarget;
+}
+
+void Surface::setBoundTexture(gl::Texture2D *texture)
+{
+ mTexture = texture;
+}
+
+gl::Texture2D *Surface::getBoundTexture() const
+{
+ return mTexture;
+}
+
+D3DFORMAT Surface::getFormat() const
+{
+ return mConfig->mRenderTargetFormat;
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/Surface.h b/Source/ThirdParty/ANGLE/src/libEGL/Surface.h
new file mode 100644
index 000000000..99c4b6769
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/Surface.h
@@ -0,0 +1,105 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Surface.h: Defines the egl::Surface class, representing a drawing surface
+// such as the client area of a window, including any back buffers.
+// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3.
+
+#ifndef INCLUDE_SURFACE_H_
+#define INCLUDE_SURFACE_H_
+
+#define EGLAPI
+#include <EGL/egl.h>
+#include <d3d9.h>
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+class Texture2D;
+}
+
+namespace egl
+{
+class Display;
+class Config;
+
+class Surface
+{
+ public:
+ Surface(Display *display, const egl::Config *config, HWND window);
+ Surface(Display *display, const egl::Config *config, HANDLE shareHandle, EGLint width, EGLint height, EGLenum textureFormat, EGLenum textureTarget);
+
+ ~Surface();
+
+ bool initialize();
+ void release();
+ bool resetSwapChain();
+
+ HWND getWindowHandle();
+ bool swap();
+
+ virtual EGLint getWidth() const;
+ virtual EGLint getHeight() const;
+
+ virtual IDirect3DSurface9 *getRenderTarget();
+ virtual IDirect3DSurface9 *getDepthStencil();
+ virtual IDirect3DTexture9 *getOffscreenTexture();
+
+ HANDLE getShareHandle() { return mShareHandle; }
+
+ void setSwapInterval(EGLint interval);
+ bool checkForOutOfDateSwapChain(); // Returns true if swapchain changed due to resize or interval update
+
+ virtual EGLenum getTextureFormat() const;
+ virtual EGLenum getTextureTarget() const;
+ virtual D3DFORMAT getFormat() const;
+
+ virtual void setBoundTexture(gl::Texture2D *texture);
+ virtual gl::Texture2D *getBoundTexture() const;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(Surface);
+
+ Display *const mDisplay;
+ IDirect3DSwapChain9 *mSwapChain;
+ IDirect3DSurface9 *mDepthStencil;
+ IDirect3DSurface9* mRenderTarget;
+ IDirect3DTexture9* mOffscreenTexture;
+
+ HANDLE mShareHandle;
+
+ void subclassWindow();
+ void unsubclassWindow();
+ bool resetSwapChain(int backbufferWidth, int backbufferHeight);
+ static DWORD convertInterval(EGLint interval);
+
+ const HWND mWindow; // Window that the surface is created for.
+ bool mWindowSubclassed; // Indicates whether we successfully subclassed mWindow for WM_RESIZE hooking
+ const egl::Config *mConfig; // EGL config surface was created with
+ EGLint mHeight; // Height of surface
+ EGLint mWidth; // Width of surface
+// EGLint horizontalResolution; // Horizontal dot pitch
+// EGLint verticalResolution; // Vertical dot pitch
+// EGLBoolean largestPBuffer; // If true, create largest pbuffer possible
+// EGLBoolean mipmapTexture; // True if texture has mipmaps
+// EGLint mipmapLevel; // Mipmap level to render to
+// EGLenum multisampleResolve; // Multisample resolve behavior
+ EGLint mPixelAspectRatio; // Display aspect ratio
+ EGLenum mRenderBuffer; // Render buffer
+ EGLenum mSwapBehavior; // Buffer swap behavior
+ EGLenum mTextureFormat; // Format of texture: RGB, RGBA, or no texture
+ EGLenum mTextureTarget; // Type of texture: 2D or no texture
+// EGLenum vgAlphaFormat; // Alpha format for OpenVG
+// EGLenum vgColorSpace; // Color space for OpenVG
+ EGLint mSwapInterval;
+ DWORD mPresentInterval;
+ bool mPresentIntervalDirty;
+ gl::Texture2D *mTexture;
+};
+}
+
+#endif // INCLUDE_SURFACE_H_
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp
new file mode 100644
index 000000000..8689a4ecc
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.cpp
@@ -0,0 +1,1170 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// libEGL.cpp: Implements the exported EGL functions.
+
+#include <exception>
+
+#include "common/debug.h"
+#include "common/version.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/Texture.h"
+
+#include "libEGL/main.h"
+#include "libEGL/Display.h"
+
+
+bool validateDisplay(egl::Display *display)
+{
+ if (display == EGL_NO_DISPLAY)
+ {
+ return error(EGL_BAD_DISPLAY, false);
+ }
+
+ if (!display->isInitialized())
+ {
+ return error(EGL_NOT_INITIALIZED, false);
+ }
+
+ return true;
+}
+
+bool validateConfig(egl::Display *display, EGLConfig config)
+{
+ if (!validateDisplay(display))
+ {
+ return false;
+ }
+
+ if (!display->isValidConfig(config))
+ {
+ return error(EGL_BAD_CONFIG, false);
+ }
+
+ return true;
+}
+
+bool validateContext(egl::Display *display, gl::Context *context)
+{
+ if (!validateDisplay(display))
+ {
+ return false;
+ }
+
+ if (!display->isValidContext(context))
+ {
+ return error(EGL_BAD_CONTEXT, false);
+ }
+
+ return true;
+}
+
+bool validateSurface(egl::Display *display, egl::Surface *surface)
+{
+ if (!validateDisplay(display))
+ {
+ return false;
+ }
+
+ if (!display->isValidSurface(surface))
+ {
+ return error(EGL_BAD_SURFACE, false);
+ }
+
+ return true;
+}
+
+extern "C"
+{
+EGLint __stdcall eglGetError(void)
+{
+ EVENT("()");
+
+ EGLint error = egl::getCurrentError();
+
+ if (error != EGL_SUCCESS)
+ {
+ egl::setCurrentError(EGL_SUCCESS);
+ }
+
+ return error;
+}
+
+EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id)
+{
+ EVENT("(EGLNativeDisplayType display_id = 0x%0.8p)", display_id);
+
+ try
+ {
+ // FIXME: Return the same EGLDisplay handle when display_id already created a display
+
+ if (display_id == EGL_DEFAULT_DISPLAY)
+ {
+ return new egl::Display((HDC)NULL);
+ }
+ else
+ {
+ // FIXME: Check if display_id is a valid display device context
+
+ return new egl::Display((HDC)display_id);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY);
+ }
+
+ return EGL_NO_DISPLAY;
+}
+
+EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p)",
+ dpy, major, minor);
+
+ try
+ {
+ if (dpy == EGL_NO_DISPLAY)
+ {
+ return error(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!display->initialize())
+ {
+ return error(EGL_NOT_INITIALIZED, EGL_FALSE);
+ }
+
+ if (major) *major = 1;
+ if (minor) *minor = 4;
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglTerminate(EGLDisplay dpy)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p)", dpy);
+
+ try
+ {
+ if (dpy == EGL_NO_DISPLAY)
+ {
+ return error(EGL_BAD_DISPLAY, EGL_FALSE);
+ }
+
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ display->terminate();
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint name = %d)", dpy, name);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateDisplay(display))
+ {
+ return NULL;
+ }
+
+ switch (name)
+ {
+ case EGL_CLIENT_APIS:
+ return success("OpenGL_ES");
+ case EGL_EXTENSIONS:
+ return display->getExtensionString();
+ case EGL_VENDOR:
+ return success("Google Inc.");
+ case EGL_VERSION:
+ return success("1.4 (ANGLE "VERSION_STRING")");
+ }
+
+ return error(EGL_BAD_PARAMETER, (const char*)NULL);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, (const char*)NULL);
+ }
+
+ return NULL;
+}
+
+EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, "
+ "EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
+ dpy, configs, config_size, num_config);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateDisplay(display))
+ {
+ return EGL_FALSE;
+ }
+
+ if (!num_config)
+ {
+ return error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ const EGLint attribList[] = {EGL_NONE};
+
+ if (!display->getConfigs(configs, attribList, config_size, num_config))
+ {
+ return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, "
+ "EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p)",
+ dpy, attrib_list, configs, config_size, num_config);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateDisplay(display))
+ {
+ return EGL_FALSE;
+ }
+
+ if (!num_config)
+ {
+ return error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ const EGLint attribList[] = {EGL_NONE};
+
+ if (!attrib_list)
+ {
+ attrib_list = attribList;
+ }
+
+ display->getConfigs(configs, attrib_list, config_size, num_config);
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
+ dpy, config, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_FALSE;
+ }
+
+ if (!display->getConfigAttrib(config, attribute, value))
+ {
+ return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, "
+ "const EGLint *attrib_list = 0x%0.8p)", dpy, config, win, attrib_list);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_SURFACE;
+ }
+
+ HWND window = (HWND)win;
+
+ if (!IsWindow(window))
+ {
+ return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+ }
+
+ return display->createWindowSurface(window, config, attrib_list);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
+ dpy, config, attrib_list);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_SURFACE;
+ }
+
+ return display->createOffscreenSurface(config, NULL, attrib_list);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = 0x%0.8p, "
+ "const EGLint *attrib_list = 0x%0.8p)", dpy, config, pixmap, attrib_list);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_SURFACE;
+ }
+
+ UNIMPLEMENTED(); // FIXME
+
+ return success(EGL_NO_SURFACE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ display->destroySurface((egl::Surface*)surface);
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
+ dpy, surface, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = (egl::Surface*)surface;
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ switch (attribute)
+ {
+ case EGL_VG_ALPHA_FORMAT:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_VG_COLORSPACE:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_CONFIG_ID:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_HEIGHT:
+ *value = eglSurface->getHeight();
+ break;
+ case EGL_HORIZONTAL_RESOLUTION:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_LARGEST_PBUFFER:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_MIPMAP_TEXTURE:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_MIPMAP_LEVEL:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_MULTISAMPLE_RESOLVE:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_PIXEL_ASPECT_RATIO:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_RENDER_BUFFER:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_SWAP_BEHAVIOR:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_TEXTURE_FORMAT:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_TEXTURE_TARGET:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_VERTICAL_RESOLUTION:
+ UNIMPLEMENTED(); // FIXME
+ break;
+ case EGL_WIDTH:
+ *value = eglSurface->getWidth();
+ break;
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglQuerySurfacePointerANGLE(EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value)
+{
+ TRACE("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, void **value = 0x%0.8p)",
+ dpy, surface, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = (egl::Surface*)surface;
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ switch (attribute)
+ {
+ case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
+ *value = (void*) eglSurface->getShareHandle();
+ break;
+ default:
+ return error(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+ }
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglBindAPI(EGLenum api)
+{
+ EVENT("(EGLenum api = 0x%X)", api);
+
+ try
+ {
+ switch (api)
+ {
+ case EGL_OPENGL_API:
+ case EGL_OPENVG_API:
+ return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation
+ case EGL_OPENGL_ES_API:
+ break;
+ default:
+ return error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ egl::setCurrentAPI(api);
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLenum __stdcall eglQueryAPI(void)
+{
+ EVENT("()");
+
+ try
+ {
+ EGLenum API = egl::getCurrentAPI();
+
+ return success(API);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglWaitClient(void)
+{
+ EVENT("()");
+
+ try
+ {
+ UNIMPLEMENTED(); // FIXME
+
+ return success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglReleaseThread(void)
+{
+ EVENT("()");
+
+ try
+ {
+ eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, "
+ "EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p)",
+ dpy, buftype, buffer, config, attrib_list);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_SURFACE;
+ }
+
+ if (buftype != EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE || !buffer)
+ {
+ return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+
+ return display->createOffscreenSurface(config, (HANDLE)buffer, attrib_list);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d)",
+ dpy, surface, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ UNIMPLEMENTED(); // FIXME
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (buffer != EGL_BACK_BUFFER)
+ {
+ return error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
+ {
+ return error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ if (eglSurface->getBoundTexture())
+ {
+ return error(EGL_BAD_ACCESS, EGL_FALSE);
+ }
+
+ if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
+ {
+ return error(EGL_BAD_MATCH, EGL_FALSE);
+ }
+
+ glBindTexImage(eglSurface);
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d)", dpy, surface, buffer);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (buffer != EGL_BACK_BUFFER)
+ {
+ return error(EGL_BAD_PARAMETER, EGL_FALSE);
+ }
+
+ if (surface == EGL_NO_SURFACE || eglSurface->getWindowHandle())
+ {
+ return error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ if (eglSurface->getTextureFormat() == EGL_NO_TEXTURE)
+ {
+ return error(EGL_BAD_MATCH, EGL_FALSE);
+ }
+
+ gl::Texture2D *texture = eglSurface->getBoundTexture();
+
+ if (texture)
+ {
+ texture->releaseTexImage();
+ }
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLint interval = %d)", dpy, interval);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateDisplay(display))
+ {
+ return EGL_FALSE;
+ }
+
+ egl::Surface *draw_surface = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
+
+ if (draw_surface == NULL)
+ {
+ return error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ draw_surface->setSwapInterval(interval);
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, "
+ "const EGLint *attrib_list = 0x%0.8p)", dpy, config, share_context, attrib_list);
+
+ try
+ {
+ // Get the requested client version (default is 1) and check it is two.
+ EGLint client_version = 1;
+ if (attrib_list)
+ {
+ for (const EGLint* attribute = attrib_list; attribute[0] != EGL_NONE; attribute += 2)
+ {
+ if (attribute[0] == EGL_CONTEXT_CLIENT_VERSION)
+ {
+ client_version = attribute[1];
+ }
+ else
+ {
+ return error(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
+ }
+ }
+ }
+
+ if (client_version != 2)
+ {
+ return error(EGL_BAD_CONFIG, EGL_NO_CONTEXT);
+ }
+
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+
+ if (!validateConfig(display, config))
+ {
+ return EGL_NO_CONTEXT;
+ }
+
+ EGLContext context = display->createContext(config, static_cast<gl::Context*>(share_context));
+
+ return success(context);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+ }
+
+ return EGL_NO_CONTEXT;
+}
+
+EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p)", dpy, ctx);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ gl::Context *context = static_cast<gl::Context*>(ctx);
+
+ if (!validateContext(display, context))
+ {
+ return EGL_FALSE;
+ }
+
+ if (ctx == EGL_NO_CONTEXT)
+ {
+ return error(EGL_BAD_CONTEXT, EGL_FALSE);
+ }
+
+ display->destroyContext(context);
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p)",
+ dpy, draw, read, ctx);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ gl::Context *context = static_cast<gl::Context*>(ctx);
+ IDirect3DDevice9 *device = display->getDevice();
+
+ if (!device || display->isDeviceLost())
+ {
+ return error(EGL_CONTEXT_LOST, EGL_FALSE);
+ }
+
+ if (ctx != EGL_NO_CONTEXT && !validateContext(display, context))
+ {
+ return EGL_FALSE;
+ }
+
+ if ((draw != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(draw))) ||
+ (read != EGL_NO_SURFACE && !validateSurface(display, static_cast<egl::Surface*>(read))))
+ {
+ return EGL_FALSE;
+ }
+
+ if (draw != read)
+ {
+ UNIMPLEMENTED(); // FIXME
+ }
+
+ egl::Surface* previousDraw = static_cast<egl::Surface*>(egl::getCurrentDrawSurface());
+ egl::Surface* previousRead = static_cast<egl::Surface*>(egl::getCurrentReadSurface());
+
+ egl::setCurrentDisplay(dpy);
+ egl::setCurrentDrawSurface(draw);
+ egl::setCurrentReadSurface(read);
+
+ glMakeCurrent(context, display, static_cast<egl::Surface*>(draw));
+
+ return success(EGL_TRUE);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLContext __stdcall eglGetCurrentContext(void)
+{
+ EVENT("()");
+
+ try
+ {
+ EGLContext context = glGetCurrentContext();
+
+ return success(context);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+ }
+
+ return EGL_NO_CONTEXT;
+}
+
+EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw)
+{
+ EVENT("(EGLint readdraw = %d)", readdraw);
+
+ try
+ {
+ if (readdraw == EGL_READ)
+ {
+ EGLSurface read = egl::getCurrentReadSurface();
+ return success(read);
+ }
+ else if (readdraw == EGL_DRAW)
+ {
+ EGLSurface draw = egl::getCurrentDrawSurface();
+ return success(draw);
+ }
+ else
+ {
+ return error(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+ }
+
+ return EGL_NO_SURFACE;
+}
+
+EGLDisplay __stdcall eglGetCurrentDisplay(void)
+{
+ EVENT("()");
+
+ try
+ {
+ EGLDisplay dpy = egl::getCurrentDisplay();
+
+ return success(dpy);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY);
+ }
+
+ return EGL_NO_DISPLAY;
+}
+
+EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p)",
+ dpy, ctx, attribute, value);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ gl::Context *context = static_cast<gl::Context*>(ctx);
+
+ if (!validateContext(display, context))
+ {
+ return EGL_FALSE;
+ }
+
+ UNIMPLEMENTED(); // FIXME
+
+ return success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglWaitGL(void)
+{
+ EVENT("()");
+
+ try
+ {
+ UNIMPLEMENTED(); // FIXME
+
+ return success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglWaitNative(EGLint engine)
+{
+ EVENT("(EGLint engine = %d)", engine);
+
+ try
+ {
+ UNIMPLEMENTED(); // FIXME
+
+ return success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p)", dpy, surface);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = (egl::Surface*)surface;
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ if (surface == EGL_NO_SURFACE)
+ {
+ return error(EGL_BAD_SURFACE, EGL_FALSE);
+ }
+
+ if (eglSurface->swap())
+ {
+ return success(EGL_TRUE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target)
+{
+ EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p)", dpy, surface, target);
+
+ try
+ {
+ egl::Display *display = static_cast<egl::Display*>(dpy);
+ egl::Surface *eglSurface = static_cast<egl::Surface*>(surface);
+
+ if (!validateSurface(display, eglSurface))
+ {
+ return EGL_FALSE;
+ }
+
+ UNIMPLEMENTED(); // FIXME
+
+ return success(0);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, EGL_FALSE);
+ }
+
+ return EGL_FALSE;
+}
+
+__eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname)
+{
+ EVENT("(const char *procname = \"%s\")", procname);
+
+ try
+ {
+ struct Extension
+ {
+ const char *name;
+ __eglMustCastToProperFunctionPointerType address;
+ };
+
+ static const Extension eglExtensions[] =
+ {
+ {"eglQuerySurfacePointerANGLE", (__eglMustCastToProperFunctionPointerType)eglQuerySurfacePointerANGLE},
+ {"", NULL},
+ };
+
+ for (int ext = 0; ext < sizeof(eglExtensions) / sizeof(Extension); ext++)
+ {
+ if (strcmp(procname, eglExtensions[ext].name) == 0)
+ {
+ return (__eglMustCastToProperFunctionPointerType)eglExtensions[ext].address;
+ }
+ }
+
+ return glGetProcAddress(procname);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(EGL_BAD_ALLOC, (__eglMustCastToProperFunctionPointerType)NULL);
+ }
+
+ return NULL;
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/libEGL.def b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.def
new file mode 100644
index 000000000..71a5e6797
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.def
@@ -0,0 +1,36 @@
+LIBRARY libEGL
+EXPORTS
+ eglBindAPI @14
+ eglBindTexImage @20
+ eglChooseConfig @7
+ eglCopyBuffers @33
+ eglCreateContext @23
+ eglCreatePbufferFromClientBuffer @18
+ eglCreatePbufferSurface @10
+ eglCreatePixmapSurface @11
+ eglCreateWindowSurface @9
+ eglDestroyContext @24
+ eglDestroySurface @12
+ eglGetConfigAttrib @8
+ eglGetConfigs @6
+ eglGetCurrentContext @26
+ eglGetCurrentDisplay @28
+ eglGetCurrentSurface @27
+ eglGetDisplay @2
+ eglGetError @1
+ eglGetProcAddress @34
+ eglInitialize @3
+ eglMakeCurrent @25
+ eglQueryAPI @15
+ eglQueryContext @29
+ eglQueryString @5
+ eglQuerySurface @13
+ eglReleaseTexImage @21
+ eglReleaseThread @17
+ eglSurfaceAttrib @19
+ eglSwapBuffers @32
+ eglSwapInterval @22
+ eglTerminate @4
+ eglWaitClient @16
+ eglWaitGL @30
+ eglWaitNative @31 \ No newline at end of file
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/libEGL.rc b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.rc
new file mode 100644
index 000000000..15ed28562
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "../common/version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "#include ""../common/version.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "ANGLE libEGL Dynamic Link Library"
+ VALUE "FileVersion", VERSION_STRING
+ VALUE "InternalName", "libEGL"
+ VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc."
+ VALUE "OriginalFilename", "libEGL.dll"
+ VALUE "PrivateBuild", VERSION_STRING
+ VALUE "ProductName", "ANGLE libEGL Dynamic Link Library"
+ VALUE "ProductVersion", VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/libEGL.vcproj b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.vcproj
new file mode 100644
index 000000000..676bc988b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/libEGL.vcproj
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libEGL"
+ ProjectGUID="{E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}"
+ RootNamespace="libEGL"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(ProjectDir)/..; $(ProjectDir)/../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBEGL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="d3d9.lib dxguid.lib dwmapi.lib"
+ LinkIncremental="2"
+ ModuleDefinitionFile="libEGL.def"
+ DelayLoadDLLs="dwmapi.dll"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="@echo on&#x0D;&#x0A;mkdir &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;copy &quot;$(OutDir)\libEGL.dll&quot; &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;copy &quot;$(OutDir)\libEGL.lib&quot; &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;@echo off&#x0D;&#x0A;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="2"
+ AdditionalIncludeDirectories="$(ProjectDir)/..; $(ProjectDir)/../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBEGL_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="d3d9.lib dxguid.lib dwmapi.lib"
+ LinkIncremental="1"
+ ModuleDefinitionFile="libEGL.def"
+ DelayLoadDLLs="dwmapi.lib"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="@echo on&#x0D;&#x0A;mkdir &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;copy &quot;$(OutDir)\libEGL.dll&quot; &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;copy &quot;$(OutDir)\libEGL.lib&quot; &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;@echo off&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\Config.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Common\debug.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Display.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\libEGL.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Surface.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\Config.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Display.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\EGL\egl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\EGL\eglext.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\EGL\eglplatform.h"
+ >
+ </File>
+ <File
+ RelativePath=".\main.h"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Surface.h"
+ >
+ </File>
+ <File
+ RelativePath="..\common\version.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\libEGL.def"
+ >
+ </File>
+ <File
+ RelativePath=".\libEGL.rc"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/main.cpp b/Source/ThirdParty/ANGLE/src/libEGL/main.cpp
new file mode 100644
index 000000000..1c107bf56
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/main.cpp
@@ -0,0 +1,161 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// main.cpp: DLL entry point and management of thread-local data.
+
+#include "libEGL/main.h"
+
+#include "common/debug.h"
+
+static DWORD currentTLS = TLS_OUT_OF_INDEXES;
+
+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+#if !defined(ANGLE_DISABLE_TRACE)
+ FILE *debug = fopen(TRACE_OUTPUT_FILE, "rt");
+
+ if (debug)
+ {
+ fclose(debug);
+ debug = fopen(TRACE_OUTPUT_FILE, "wt"); // Erase
+ fclose(debug);
+ }
+#endif
+
+ currentTLS = TlsAlloc();
+
+ if (currentTLS == TLS_OUT_OF_INDEXES)
+ {
+ return FALSE;
+ }
+ }
+ // Fall throught to initialize index
+ case DLL_THREAD_ATTACH:
+ {
+ egl::Current *current = (egl::Current*)LocalAlloc(LPTR, sizeof(egl::Current));
+
+ if (current)
+ {
+ TlsSetValue(currentTLS, current);
+
+ current->error = EGL_SUCCESS;
+ current->API = EGL_OPENGL_ES_API;
+ current->display = EGL_NO_DISPLAY;
+ current->drawSurface = EGL_NO_SURFACE;
+ current->readSurface = EGL_NO_SURFACE;
+ }
+ }
+ break;
+ case DLL_THREAD_DETACH:
+ {
+ void *current = TlsGetValue(currentTLS);
+
+ if (current)
+ {
+ LocalFree((HLOCAL)current);
+ }
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ {
+ void *current = TlsGetValue(currentTLS);
+
+ if (current)
+ {
+ LocalFree((HLOCAL)current);
+ }
+
+ TlsFree(currentTLS);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+namespace egl
+{
+void setCurrentError(EGLint error)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->error = error;
+}
+
+EGLint getCurrentError()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->error;
+}
+
+void setCurrentAPI(EGLenum API)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->API = API;
+}
+
+EGLenum getCurrentAPI()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->API;
+}
+
+void setCurrentDisplay(EGLDisplay dpy)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->display = dpy;
+}
+
+EGLDisplay getCurrentDisplay()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->display;
+}
+
+void setCurrentDrawSurface(EGLSurface surface)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->drawSurface = surface;
+}
+
+EGLSurface getCurrentDrawSurface()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->drawSurface;
+}
+
+void setCurrentReadSurface(EGLSurface surface)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->readSurface = surface;
+}
+
+EGLSurface getCurrentReadSurface()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->readSurface;
+}
+}
+
+void error(EGLint errorCode)
+{
+ egl::setCurrentError(errorCode);
+}
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/main.h b/Source/ThirdParty/ANGLE/src/libEGL/main.h
new file mode 100644
index 000000000..d09d9e6bc
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/main.h
@@ -0,0 +1,61 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// main.h: Management of thread-local data.
+
+#ifndef LIBEGL_MAIN_H_
+#define LIBEGL_MAIN_H_
+
+#define EGLAPI
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+namespace egl
+{
+struct Current
+{
+ EGLint error;
+ EGLenum API;
+ EGLDisplay display;
+ EGLSurface drawSurface;
+ EGLSurface readSurface;
+};
+
+void setCurrentError(EGLint error);
+EGLint getCurrentError();
+
+void setCurrentAPI(EGLenum API);
+EGLenum getCurrentAPI();
+
+void setCurrentDisplay(EGLDisplay dpy);
+EGLDisplay getCurrentDisplay();
+
+void setCurrentDrawSurface(EGLSurface surface);
+EGLSurface getCurrentDrawSurface();
+
+void setCurrentReadSurface(EGLSurface surface);
+EGLSurface getCurrentReadSurface();
+}
+
+void error(EGLint errorCode);
+
+template<class T>
+const T &error(EGLint errorCode, const T &returnValue)
+{
+ error(errorCode);
+
+ return returnValue;
+}
+
+template<class T>
+const T &success(const T &returnValue)
+{
+ egl::setCurrentError(EGL_SUCCESS);
+
+ return returnValue;
+}
+
+#endif // LIBEGL_MAIN_H_
diff --git a/Source/ThirdParty/ANGLE/src/libEGL/resource.h b/Source/ThirdParty/ANGLE/src/libEGL/resource.h
new file mode 100644
index 000000000..3921f4c07
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libEGL/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by libEGL.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.cpp
new file mode 100644
index 000000000..923a9de07
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.cpp
@@ -0,0 +1,599 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Blit.cpp: Surface copy utility class.
+
+#include "libGLESv2/Blit.h"
+
+#include <d3dx9.h>
+
+#include "common/debug.h"
+
+#include "libGLESv2/main.h"
+
+namespace
+{
+// Standard Vertex Shader
+// Input 0 is the homogenous position.
+// Outputs the homogenous position as-is.
+// Outputs a tex coord with (0,0) in the upper-left corner of the screen and (1,1) in the bottom right.
+// C0.X must be negative half-pixel width, C0.Y must be half-pixel height. C0.ZW must be 0.
+const char standardvs[] =
+"struct VS_OUTPUT\n"
+"{\n"
+" float4 position : POSITION;\n"
+" float4 texcoord : TEXCOORD0;\n"
+"};\n"
+"\n"
+"uniform float4 halfPixelSize : c0;\n"
+"\n"
+"VS_OUTPUT main(in float4 position : POSITION)\n"
+"{\n"
+" VS_OUTPUT Out;\n"
+"\n"
+" Out.position = position + halfPixelSize;\n"
+" Out.texcoord = position * float4(0.5, -0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0);\n"
+"\n"
+" return Out;\n"
+"}\n";
+
+// Flip Y Vertex Shader
+// Input 0 is the homogenous position.
+// Outputs the homogenous position as-is.
+// Outputs a tex coord with (0,1) in the upper-left corner of the screen and (1,0) in the bottom right.
+// C0.XY must be the half-pixel width and height. C0.ZW must be 0.
+const char flipyvs[] =
+"struct VS_OUTPUT\n"
+"{\n"
+" float4 position : POSITION;\n"
+" float4 texcoord : TEXCOORD0;\n"
+"};\n"
+"\n"
+"uniform float4 halfPixelSize : c0;\n"
+"\n"
+"VS_OUTPUT main(in float4 position : POSITION)\n"
+"{\n"
+" VS_OUTPUT Out;\n"
+"\n"
+" Out.position = position + halfPixelSize;\n"
+" Out.texcoord = position * float4(0.5, 0.5, 1.0, 1.0) + float4(0.5, 0.5, 0, 0);\n"
+"\n"
+" return Out;\n"
+"}\n";
+
+// Passthrough Pixel Shader
+// Outputs texture 0 sampled at texcoord 0.
+const char passthroughps[] =
+"sampler2D tex : s0;\n"
+"\n"
+"float4 main(float4 texcoord : TEXCOORD0) : COLOR\n"
+"{\n"
+" return tex2D(tex, texcoord.xy);\n"
+"}\n";
+
+// Luminance Conversion Pixel Shader
+// Outputs sample(tex0, tc0).rrra.
+// For LA output (pass A) set C0.X = 1, C0.Y = 0.
+// For L output (A = 1) set C0.X = 0, C0.Y = 1.
+const char luminanceps[] =
+"sampler2D tex : s0;\n"
+"\n"
+"uniform float4 mode : c0;\n"
+"\n"
+"float4 main(float4 texcoord : TEXCOORD0) : COLOR\n"
+"{\n"
+" float4 tmp = tex2D(tex, texcoord.xy);\n"
+" tmp.w = tmp.w * mode.x + mode.y;\n"
+" return tmp.xxxw;\n"
+"}\n";
+
+// RGB/A Component Mask Pixel Shader
+// Outputs sample(tex0, tc0) with options to force RGB = 0 and/or A = 1.
+// To force RGB = 0, set C0.X = 0, otherwise C0.X = 1.
+// To force A = 1, set C0.Z = 0, C0.W = 1, otherwise C0.Z = 1, C0.W = 0.
+const char componentmaskps[] =
+"sampler2D tex : s0;\n"
+"\n"
+"uniform float4 mode : c0;\n"
+"\n"
+"float4 main(float4 texcoord : TEXCOORD0) : COLOR\n"
+"{\n"
+" float4 tmp = tex2D(tex, texcoord.xy);\n"
+" tmp.xyz = tmp.xyz * mode.x;\n"
+" tmp.w = tmp.w * mode.z + mode.w;\n"
+" return tmp;\n"
+"}\n";
+
+}
+
+namespace gl
+{
+
+const char * const Blit::mShaderSource[] =
+{
+ standardvs,
+ flipyvs,
+ passthroughps,
+ luminanceps,
+ componentmaskps
+};
+
+Blit::Blit(Context *context)
+ : mContext(context), mQuadVertexBuffer(NULL), mQuadVertexDeclaration(NULL), mSavedRenderTarget(NULL), mSavedDepthStencil(NULL), mSavedStateBlock(NULL)
+{
+ initGeometry();
+ memset(mCompiledShaders, 0, sizeof(mCompiledShaders));
+}
+
+Blit::~Blit()
+{
+ if (mSavedStateBlock) mSavedStateBlock->Release();
+ if (mQuadVertexBuffer) mQuadVertexBuffer->Release();
+ if (mQuadVertexDeclaration) mQuadVertexDeclaration->Release();
+
+ for (int i = 0; i < SHADER_COUNT; i++)
+ {
+ if (mCompiledShaders[i])
+ {
+ mCompiledShaders[i]->Release();
+ }
+ }
+}
+
+void Blit::initGeometry()
+{
+ static const float quad[] =
+ {
+ -1, -1,
+ -1, 1,
+ 1, -1,
+ 1, 1
+ };
+
+ IDirect3DDevice9 *device = getDevice();
+
+ HRESULT result = device->CreateVertexBuffer(sizeof(quad), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &mQuadVertexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ void *lockPtr = NULL;
+ result = mQuadVertexBuffer->Lock(0, 0, &lockPtr, 0);
+
+ if (FAILED(result) || lockPtr == NULL)
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ memcpy(lockPtr, quad, sizeof(quad));
+ mQuadVertexBuffer->Unlock();
+
+ static const D3DVERTEXELEMENT9 elements[] =
+ {
+ { 0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
+ D3DDECL_END()
+ };
+
+ result = device->CreateVertexDeclaration(elements, &mQuadVertexDeclaration);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+template <class D3DShaderType>
+bool Blit::setShader(ShaderId source, const char *profile,
+ HRESULT (WINAPI IDirect3DDevice9::*createShader)(const DWORD *, D3DShaderType**),
+ HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ D3DShaderType *shader;
+
+ if (mCompiledShaders[source] != NULL)
+ {
+ shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
+ }
+ else
+ {
+ ID3DXBuffer *shaderCode;
+ HRESULT hr = D3DXCompileShader(mShaderSource[source], strlen(mShaderSource[source]), NULL, NULL, "main", profile, 0, &shaderCode, NULL, NULL);
+
+ if (FAILED(hr))
+ {
+ ERR("Failed to compile %s shader for blit operation %d, error 0x%08X.", profile, (int)source, hr);
+ return false;
+ }
+
+ hr = (device->*createShader)(static_cast<const DWORD*>(shaderCode->GetBufferPointer()), &shader);
+ if (FAILED(hr))
+ {
+ shaderCode->Release();
+ ERR("Failed to create %s shader for blit operation %d, error 0x%08X.", profile, (int)source, hr);
+ return false;
+ }
+
+ shaderCode->Release();
+
+ mCompiledShaders[source] = shader;
+ }
+
+ HRESULT hr = (device->*setShader)(shader);
+
+ if (FAILED(hr))
+ {
+ ERR("Failed to set %s shader for blit operation %d, error 0x%08X.", profile, (int)source, hr);
+ return false;
+ }
+
+ return true;
+}
+
+bool Blit::setVertexShader(ShaderId shader)
+{
+ return setShader<IDirect3DVertexShader9>(shader, mContext->supportsShaderModel3() ? "vs_3_0" : "vs_2_0", &IDirect3DDevice9::CreateVertexShader, &IDirect3DDevice9::SetVertexShader);
+}
+
+bool Blit::setPixelShader(ShaderId shader)
+{
+ return setShader<IDirect3DPixelShader9>(shader, mContext->supportsShaderModel3() ? "ps_3_0" : "ps_2_0", &IDirect3DDevice9::CreatePixelShader, &IDirect3DDevice9::SetPixelShader);
+}
+
+RECT Blit::getSurfaceRect(IDirect3DSurface9 *surface) const
+{
+ D3DSURFACE_DESC desc;
+ surface->GetDesc(&desc);
+
+ RECT rect;
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = desc.Width;
+ rect.bottom = desc.Height;
+
+ return rect;
+}
+
+bool Blit::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
+{
+ IDirect3DTexture9 *texture = copySurfaceToTexture(source, getSurfaceRect(source));
+ if (!texture)
+ {
+ return false;
+ }
+
+ IDirect3DDevice9 *device = getDevice();
+
+ saveState();
+
+ device->SetTexture(0, texture);
+ device->SetRenderTarget(0, dest);
+
+ setVertexShader(SHADER_VS_STANDARD);
+ setPixelShader(SHADER_PS_PASSTHROUGH);
+
+ setCommonBlitState();
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+
+ setViewport(getSurfaceRect(dest), 0, 0);
+
+ render();
+
+ texture->Release();
+
+ restoreState();
+
+ return true;
+}
+
+bool Blit::copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ D3DSURFACE_DESC sourceDesc;
+ D3DSURFACE_DESC destDesc;
+ source->GetDesc(&sourceDesc);
+ dest->GetDesc(&destDesc);
+
+ if (sourceDesc.Format == destDesc.Format && destDesc.Usage & D3DUSAGE_RENDERTARGET) // Can use StretchRect
+ {
+ RECT destRect = {xoffset, yoffset, xoffset + (sourceRect.right - sourceRect.left), yoffset + (sourceRect.bottom - sourceRect.top)};
+ HRESULT result = device->StretchRect(source, &sourceRect, dest, &destRect, D3DTEXF_POINT);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY, false);
+ }
+ }
+ else
+ {
+ return formatConvert(source, sourceRect, destFormat, xoffset, yoffset, dest);
+ }
+
+ return true;
+}
+
+bool Blit::formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest)
+{
+ IDirect3DTexture9 *texture = copySurfaceToTexture(source, sourceRect);
+ if (!texture)
+ {
+ return false;
+ }
+
+ IDirect3DDevice9 *device = getDevice();
+
+ saveState();
+
+ device->SetTexture(0, texture);
+ device->SetRenderTarget(0, dest);
+
+ setViewport(sourceRect, xoffset, yoffset);
+
+ setCommonBlitState();
+ if (setFormatConvertShaders(destFormat))
+ {
+ render();
+ }
+
+ texture->Release();
+
+ restoreState();
+
+ return true;
+}
+
+bool Blit::setFormatConvertShaders(GLenum destFormat)
+{
+ bool okay = setVertexShader(SHADER_VS_STANDARD);
+
+ switch (destFormat)
+ {
+ default: UNREACHABLE();
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ case GL_RGB:
+ case GL_ALPHA:
+ okay = okay && setPixelShader(SHADER_PS_COMPONENTMASK);
+ break;
+
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ okay = okay && setPixelShader(SHADER_PS_LUMINANCE);
+ break;
+ }
+
+ if (!okay)
+ {
+ return false;
+ }
+
+ enum { X = 0, Y = 1, Z = 2, W = 3 };
+
+ // The meaning of this constant depends on the shader that was selected.
+ // See the shader assembly code above for details.
+ float psConst0[4] = { 0, 0, 0, 0 };
+
+ switch (destFormat)
+ {
+ default: UNREACHABLE();
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ psConst0[X] = 1;
+ psConst0[Z] = 1;
+ break;
+
+ case GL_RGB:
+ psConst0[X] = 1;
+ psConst0[W] = 1;
+ break;
+
+ case GL_ALPHA:
+ psConst0[Z] = 1;
+ break;
+
+ case GL_LUMINANCE:
+ psConst0[Y] = 1;
+ break;
+
+ case GL_LUMINANCE_ALPHA:
+ psConst0[X] = 1;
+ break;
+ }
+
+ getDevice()->SetPixelShaderConstantF(0, psConst0, 1);
+
+ return true;
+}
+
+IDirect3DTexture9 *Blit::copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect)
+{
+ if (!surface)
+ {
+ return NULL;
+ }
+
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+
+ D3DSURFACE_DESC sourceDesc;
+ surface->GetDesc(&sourceDesc);
+
+ // Copy the render target into a texture
+ IDirect3DTexture9 *texture;
+ HRESULT result = device->CreateTexture(sourceRect.right - sourceRect.left, sourceRect.bottom - sourceRect.top, 1, D3DUSAGE_RENDERTARGET, sourceDesc.Format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
+ }
+
+ IDirect3DSurface9 *textureSurface;
+ result = texture->GetSurfaceLevel(0, &textureSurface);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ texture->Release();
+ return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
+ }
+
+ display->endScene();
+ result = device->StretchRect(surface, &sourceRect, textureSurface, NULL, D3DTEXF_NONE);
+
+ textureSurface->Release();
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ texture->Release();
+ return error(GL_OUT_OF_MEMORY, (IDirect3DTexture9*)NULL);
+ }
+
+ return texture;
+}
+
+void Blit::setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset)
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ D3DVIEWPORT9 vp;
+ vp.X = xoffset;
+ vp.Y = yoffset;
+ vp.Width = sourceRect.right - sourceRect.left;
+ vp.Height = sourceRect.bottom - sourceRect.top;
+ vp.MinZ = 0.0f;
+ vp.MaxZ = 1.0f;
+ device->SetViewport(&vp);
+
+ float halfPixelAdjust[4] = { -1.0f/vp.Width, 1.0f/vp.Height, 0, 0 };
+ device->SetVertexShaderConstantF(0, halfPixelAdjust, 1);
+}
+
+void Blit::setCommonBlitState()
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ device->SetDepthStencilSurface(NULL);
+
+ device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
+ device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE);
+ device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
+
+ device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
+ device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+
+ RECT scissorRect = {0}; // Scissoring is disabled for flipping, but we need this to capture and restore the old rectangle
+ device->SetScissorRect(&scissorRect);
+}
+
+void Blit::render()
+{
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+
+ HRESULT hr = device->SetStreamSource(0, mQuadVertexBuffer, 0, 2 * sizeof(float));
+ hr = device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+ display->startScene();
+ hr = device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
+}
+
+void Blit::saveState()
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ HRESULT hr;
+
+ device->GetDepthStencilSurface(&mSavedDepthStencil);
+ device->GetRenderTarget(0, &mSavedRenderTarget);
+
+ if (mSavedStateBlock == NULL)
+ {
+ hr = device->BeginStateBlock();
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+ setCommonBlitState();
+
+ static const float dummyConst[4] = { 0, 0, 0, 0 };
+
+ device->SetVertexShader(NULL);
+ device->SetVertexShaderConstantF(0, dummyConst, 1);
+ device->SetPixelShader(NULL);
+ device->SetPixelShaderConstantF(0, dummyConst, 1);
+
+ D3DVIEWPORT9 dummyVp;
+ dummyVp.X = 0;
+ dummyVp.Y = 0;
+ dummyVp.Width = 1;
+ dummyVp.Height = 1;
+ dummyVp.MinZ = 0;
+ dummyVp.MaxZ = 1;
+
+ device->SetViewport(&dummyVp);
+
+ device->SetTexture(0, NULL);
+
+ device->SetStreamSource(0, mQuadVertexBuffer, 0, 0);
+
+ device->SetVertexDeclaration(mQuadVertexDeclaration);
+
+ hr = device->EndStateBlock(&mSavedStateBlock);
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+ }
+
+ ASSERT(mSavedStateBlock != NULL);
+
+ if (mSavedStateBlock != NULL)
+ {
+ hr = mSavedStateBlock->Capture();
+ ASSERT(SUCCEEDED(hr));
+ }
+}
+
+void Blit::restoreState()
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ device->SetDepthStencilSurface(mSavedDepthStencil);
+ if (mSavedDepthStencil != NULL)
+ {
+ mSavedDepthStencil->Release();
+ mSavedDepthStencil = NULL;
+ }
+
+ device->SetRenderTarget(0, mSavedRenderTarget);
+ if (mSavedRenderTarget != NULL)
+ {
+ mSavedRenderTarget->Release();
+ mSavedRenderTarget = NULL;
+ }
+
+ ASSERT(mSavedStateBlock != NULL);
+
+ if (mSavedStateBlock != NULL)
+ {
+ mSavedStateBlock->Apply();
+ }
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.h
new file mode 100644
index 000000000..8928ecd07
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Blit.h
@@ -0,0 +1,94 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Blit.cpp: Surface copy utility class.
+
+#ifndef LIBGLESV2_BLIT_H_
+#define LIBGLESV2_BLIT_H_
+
+#include <map>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <d3d9.h>
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+class Context;
+
+class Blit
+{
+ public:
+ explicit Blit(Context *context);
+ ~Blit();
+
+ // Copy from source surface to dest surface.
+ // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left)
+ bool copy(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest);
+
+ // Copy from source surface to dest surface.
+ // sourceRect, xoffset, yoffset are in D3D coordinates (0,0 in upper-left)
+ // source is interpreted as RGBA and destFormat specifies the desired result format. For example, if destFormat = GL_RGB, the alpha channel will be forced to 0.
+ bool formatConvert(IDirect3DSurface9 *source, const RECT &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, IDirect3DSurface9 *dest);
+
+ // 2x2 box filter sample from source to dest.
+ // Requires that source is RGB(A) and dest has the same format as source.
+ bool boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest);
+
+ private:
+ Context *mContext;
+
+ IDirect3DVertexBuffer9 *mQuadVertexBuffer;
+ IDirect3DVertexDeclaration9 *mQuadVertexDeclaration;
+
+ void initGeometry();
+
+ bool setFormatConvertShaders(GLenum destFormat);
+
+ IDirect3DTexture9 *copySurfaceToTexture(IDirect3DSurface9 *surface, const RECT &sourceRect);
+ void setViewport(const RECT &sourceRect, GLint xoffset, GLint yoffset);
+ void setCommonBlitState();
+ RECT getSurfaceRect(IDirect3DSurface9 *surface) const;
+
+ // This enum is used to index mCompiledShaders and mShaderSource.
+ enum ShaderId
+ {
+ SHADER_VS_STANDARD,
+ SHADER_VS_FLIPY,
+ SHADER_PS_PASSTHROUGH,
+ SHADER_PS_LUMINANCE,
+ SHADER_PS_COMPONENTMASK,
+ SHADER_COUNT
+ };
+
+ static const char * const mShaderSource[];
+
+ // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown.
+ IUnknown *mCompiledShaders[SHADER_COUNT];
+
+ template <class D3DShaderType>
+ bool setShader(ShaderId source, const char *profile,
+ HRESULT (WINAPI IDirect3DDevice9::*createShader)(const DWORD *, D3DShaderType **),
+ HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*));
+
+ bool setVertexShader(ShaderId shader);
+ bool setPixelShader(ShaderId shader);
+ void render();
+
+ void saveState();
+ void restoreState();
+ IDirect3DStateBlock9 *mSavedStateBlock;
+ IDirect3DSurface9 *mSavedRenderTarget;
+ IDirect3DSurface9 *mSavedDepthStencil;
+
+ DISALLOW_COPY_AND_ASSIGN(Blit);
+};
+}
+
+#endif // LIBGLESV2_BLIT_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.cpp
new file mode 100644
index 000000000..2cd148e31
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.cpp
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or
+// index data. Implements GL buffer objects and related functionality.
+// [OpenGL ES 2.0.24] section 2.9 page 21.
+
+#include "libGLESv2/Buffer.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/VertexDataManager.h"
+#include "libGLESv2/IndexDataManager.h"
+
+namespace gl
+{
+
+Buffer::Buffer(GLuint id) : RefCountObject(id)
+{
+ mContents = NULL;
+ mSize = 0;
+ mUsage = GL_DYNAMIC_DRAW;
+
+ mStaticVertexBuffer = NULL;
+ mStaticIndexBuffer = NULL;
+ mUnmodifiedDataUse = 0;
+}
+
+Buffer::~Buffer()
+{
+ delete[] mContents;
+ delete mStaticVertexBuffer;
+ delete mStaticIndexBuffer;
+}
+
+void Buffer::bufferData(const void *data, GLsizeiptr size, GLenum usage)
+{
+ if (size == 0)
+ {
+ delete[] mContents;
+ mContents = NULL;
+ }
+ else if (size != mSize)
+ {
+ delete[] mContents;
+ mContents = new GLubyte[size];
+ memset(mContents, 0, size);
+ }
+
+ if (data != NULL && size > 0)
+ {
+ memcpy(mContents, data, size);
+ }
+
+ mSize = size;
+ mUsage = usage;
+
+ invalidateStaticData();
+
+ if (usage == GL_STATIC_DRAW)
+ {
+ mStaticVertexBuffer = new StaticVertexBuffer(getDevice());
+ mStaticIndexBuffer = new StaticIndexBuffer(getDevice());
+ }
+}
+
+void Buffer::bufferSubData(const void *data, GLsizeiptr size, GLintptr offset)
+{
+ memcpy(mContents + offset, data, size);
+
+ if ((mStaticVertexBuffer && mStaticVertexBuffer->size() != 0) || (mStaticIndexBuffer && mStaticIndexBuffer->size() != 0))
+ {
+ invalidateStaticData();
+ }
+}
+
+StaticVertexBuffer *Buffer::getStaticVertexBuffer()
+{
+ return mStaticVertexBuffer;
+}
+
+StaticIndexBuffer *Buffer::getStaticIndexBuffer()
+{
+ return mStaticIndexBuffer;
+}
+
+void Buffer::invalidateStaticData()
+{
+ delete mStaticVertexBuffer;
+ mStaticVertexBuffer = NULL;
+
+ delete mStaticIndexBuffer;
+ mStaticIndexBuffer = NULL;
+
+ mUnmodifiedDataUse = 0;
+}
+
+// Creates static buffers if sufficient used data has been left unmodified
+void Buffer::promoteStaticUsage(int dataSize)
+{
+ if (!mStaticVertexBuffer && !mStaticIndexBuffer)
+ {
+ mUnmodifiedDataUse += dataSize;
+
+ if (mUnmodifiedDataUse > 3 * mSize)
+ {
+ mStaticVertexBuffer = new StaticVertexBuffer(getDevice());
+ mStaticIndexBuffer = new StaticIndexBuffer(getDevice());
+ }
+ }
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.h
new file mode 100644
index 000000000..b6126267e
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Buffer.h
@@ -0,0 +1,61 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Buffer.h: Defines the gl::Buffer class, representing storage of vertex and/or
+// index data. Implements GL buffer objects and related functionality.
+// [OpenGL ES 2.0.24] section 2.9 page 21.
+
+#ifndef LIBGLESV2_BUFFER_H_
+#define LIBGLESV2_BUFFER_H_
+
+#include <cstddef>
+#include <vector>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "common/angleutils.h"
+#include "libGLESv2/RefCountObject.h"
+
+namespace gl
+{
+class StaticVertexBuffer;
+class StaticIndexBuffer;
+
+class Buffer : public RefCountObject
+{
+ public:
+ explicit Buffer(GLuint id);
+
+ virtual ~Buffer();
+
+ void bufferData(const void *data, GLsizeiptr size, GLenum usage);
+ void bufferSubData(const void *data, GLsizeiptr size, GLintptr offset);
+
+ void *data() { return mContents; }
+ size_t size() const { return mSize; }
+ GLenum usage() const { return mUsage; }
+
+ StaticVertexBuffer *getStaticVertexBuffer();
+ StaticIndexBuffer *getStaticIndexBuffer();
+ void invalidateStaticData();
+ void promoteStaticUsage(int dataSize);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Buffer);
+
+ GLubyte *mContents;
+ size_t mSize;
+ GLenum mUsage;
+
+ StaticVertexBuffer *mStaticVertexBuffer;
+ StaticIndexBuffer *mStaticIndexBuffer;
+ size_t mUnmodifiedDataUse;
+};
+
+}
+
+#endif // LIBGLESV2_BUFFER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp
new file mode 100644
index 000000000..6c973ead2
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp
@@ -0,0 +1,3766 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Context.cpp: Implements the gl::Context class, managing all GL state and performing
+// rendering operations. It is the GLES2 specific implementation of EGLContext.
+
+#include "libGLESv2/Context.h"
+
+#include <algorithm>
+
+#include "libEGL/Display.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/Blit.h"
+#include "libGLESv2/ResourceManager.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Fence.h"
+#include "libGLESv2/FrameBuffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/RenderBuffer.h"
+#include "libGLESv2/Shader.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/VertexDataManager.h"
+#include "libGLESv2/IndexDataManager.h"
+
+#undef near
+#undef far
+
+namespace
+{
+ enum { CLOSING_INDEX_BUFFER_SIZE = 4096 };
+}
+
+namespace gl
+{
+Context::Context(const egl::Config *config, const gl::Context *shareContext) : mConfig(config)
+{
+ mFenceHandleAllocator.setBaseHandle(0);
+
+ setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ mState.depthClearValue = 1.0f;
+ mState.stencilClearValue = 0;
+
+ mState.cullFace = false;
+ mState.cullMode = GL_BACK;
+ mState.frontFace = GL_CCW;
+ mState.depthTest = false;
+ mState.depthFunc = GL_LESS;
+ mState.blend = false;
+ mState.sourceBlendRGB = GL_ONE;
+ mState.sourceBlendAlpha = GL_ONE;
+ mState.destBlendRGB = GL_ZERO;
+ mState.destBlendAlpha = GL_ZERO;
+ mState.blendEquationRGB = GL_FUNC_ADD;
+ mState.blendEquationAlpha = GL_FUNC_ADD;
+ mState.blendColor.red = 0;
+ mState.blendColor.green = 0;
+ mState.blendColor.blue = 0;
+ mState.blendColor.alpha = 0;
+ mState.stencilTest = false;
+ mState.stencilFunc = GL_ALWAYS;
+ mState.stencilRef = 0;
+ mState.stencilMask = -1;
+ mState.stencilWritemask = -1;
+ mState.stencilBackFunc = GL_ALWAYS;
+ mState.stencilBackRef = 0;
+ mState.stencilBackMask = - 1;
+ mState.stencilBackWritemask = -1;
+ mState.stencilFail = GL_KEEP;
+ mState.stencilPassDepthFail = GL_KEEP;
+ mState.stencilPassDepthPass = GL_KEEP;
+ mState.stencilBackFail = GL_KEEP;
+ mState.stencilBackPassDepthFail = GL_KEEP;
+ mState.stencilBackPassDepthPass = GL_KEEP;
+ mState.polygonOffsetFill = false;
+ mState.polygonOffsetFactor = 0.0f;
+ mState.polygonOffsetUnits = 0.0f;
+ mState.sampleAlphaToCoverage = false;
+ mState.sampleCoverage = false;
+ mState.sampleCoverageValue = 1.0f;
+ mState.sampleCoverageInvert = false;
+ mState.scissorTest = false;
+ mState.dither = true;
+ mState.generateMipmapHint = GL_DONT_CARE;
+ mState.fragmentShaderDerivativeHint = GL_DONT_CARE;
+
+ mState.lineWidth = 1.0f;
+
+ mState.viewportX = 0;
+ mState.viewportY = 0;
+ mState.viewportWidth = config->mDisplayMode.Width;
+ mState.viewportHeight = config->mDisplayMode.Height;
+ mState.zNear = 0.0f;
+ mState.zFar = 1.0f;
+
+ mState.scissorX = 0;
+ mState.scissorY = 0;
+ mState.scissorWidth = config->mDisplayMode.Width;
+ mState.scissorHeight = config->mDisplayMode.Height;
+
+ mState.colorMaskRed = true;
+ mState.colorMaskGreen = true;
+ mState.colorMaskBlue = true;
+ mState.colorMaskAlpha = true;
+ mState.depthMask = true;
+
+ if (shareContext != NULL)
+ {
+ mResourceManager = shareContext->mResourceManager;
+ mResourceManager->addRef();
+ }
+ else
+ {
+ mResourceManager = new ResourceManager();
+ }
+
+ // [OpenGL ES 2.0.24] section 3.7 page 83:
+ // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional
+ // and cube map texture state vectors respectively associated with them.
+ // In order that access to these initial textures not be lost, they are treated as texture
+ // objects all of whose names are 0.
+
+ mTexture2DZero.set(new Texture2D(0));
+ mTextureCubeMapZero.set(new TextureCubeMap(0));
+
+ mState.activeSampler = 0;
+ bindArrayBuffer(0);
+ bindElementArrayBuffer(0);
+ bindTextureCubeMap(0);
+ bindTexture2D(0);
+ bindReadFramebuffer(0);
+ bindDrawFramebuffer(0);
+ bindRenderbuffer(0);
+
+ mState.currentProgram = 0;
+
+ mState.packAlignment = 4;
+ mState.unpackAlignment = 4;
+
+ mVertexDataManager = NULL;
+ mIndexDataManager = NULL;
+ mBlit = NULL;
+ mClosingIB = NULL;
+
+ mInvalidEnum = false;
+ mInvalidValue = false;
+ mInvalidOperation = false;
+ mOutOfMemory = false;
+ mInvalidFramebufferOperation = false;
+
+ mHasBeenCurrent = false;
+
+ mSupportsCompressedTextures = false;
+ mSupportsEventQueries = false;
+ mMaxSupportedSamples = 0;
+ mMaskedClearSavedState = NULL;
+ markAllStateDirty();
+}
+
+Context::~Context()
+{
+ if (mState.currentProgram != 0)
+ {
+ Program *programObject = mResourceManager->getProgram(mState.currentProgram);
+ if (programObject)
+ {
+ programObject->release();
+ }
+ mState.currentProgram = 0;
+ }
+
+ while (!mFramebufferMap.empty())
+ {
+ deleteFramebuffer(mFramebufferMap.begin()->first);
+ }
+
+ while (!mFenceMap.empty())
+ {
+ deleteFence(mFenceMap.begin()->first);
+ }
+
+ while (!mMultiSampleSupport.empty())
+ {
+ delete [] mMultiSampleSupport.begin()->second;
+ mMultiSampleSupport.erase(mMultiSampleSupport.begin());
+ }
+
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+ {
+ for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++)
+ {
+ mState.samplerTexture[type][sampler].set(NULL);
+ }
+ }
+
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+ {
+ mIncompleteTextures[type].set(NULL);
+ }
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mState.vertexAttribute[i].mBoundBuffer.set(NULL);
+ }
+
+ mState.arrayBuffer.set(NULL);
+ mState.elementArrayBuffer.set(NULL);
+ mState.renderbuffer.set(NULL);
+
+ mTexture2DZero.set(NULL);
+ mTextureCubeMapZero.set(NULL);
+
+ delete mVertexDataManager;
+ delete mIndexDataManager;
+ delete mBlit;
+ delete mClosingIB;
+
+ if (mMaskedClearSavedState)
+ {
+ mMaskedClearSavedState->Release();
+ }
+
+ mResourceManager->release();
+}
+
+void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
+{
+ IDirect3DDevice9 *device = display->getDevice();
+
+ if (!mHasBeenCurrent)
+ {
+ mDeviceCaps = display->getDeviceCaps();
+
+ mVertexDataManager = new VertexDataManager(this, device);
+ mIndexDataManager = new IndexDataManager(this, device);
+ mBlit = new Blit(this);
+
+ mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0);
+ mSupportsVertexTexture = display->getVertexTextureSupport();
+ mSupportsNonPower2Texture = display->getNonPower2TextureSupport();
+
+ mMaxTextureDimension = std::min(std::min((int)mDeviceCaps.MaxTextureWidth, (int)mDeviceCaps.MaxTextureHeight),
+ (int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE);
+ mMaxCubeTextureDimension = std::min(mMaxTextureDimension, (int)gl::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE);
+ mMaxRenderbufferDimension = mMaxTextureDimension;
+ mMaxTextureLevel = log2(mMaxTextureDimension) + 1;
+ TRACE("MaxTextureDimension=%d, MaxCubeTextureDimension=%d, MaxRenderbufferDimension=%d, MaxTextureLevel=%d",
+ mMaxTextureDimension, mMaxCubeTextureDimension, mMaxRenderbufferDimension, mMaxTextureLevel);
+
+ const D3DFORMAT renderBufferFormats[] =
+ {
+ D3DFMT_A8R8G8B8,
+ D3DFMT_X8R8G8B8,
+ D3DFMT_R5G6B5,
+ D3DFMT_D24S8
+ };
+
+ int max = 0;
+ for (int i = 0; i < sizeof(renderBufferFormats) / sizeof(D3DFORMAT); ++i)
+ {
+ bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
+ display->getMultiSampleSupport(renderBufferFormats[i], multisampleArray);
+ mMultiSampleSupport[renderBufferFormats[i]] = multisampleArray;
+
+ for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
+ {
+ if (multisampleArray[j] && j != D3DMULTISAMPLE_NONMASKABLE && j > max)
+ {
+ max = j;
+ }
+ }
+ }
+
+ mMaxSupportedSamples = max;
+
+ mSupportsEventQueries = display->getEventQuerySupport();
+ mSupportsCompressedTextures = display->getCompressedTextureSupport();
+ mSupportsFloatTextures = display->getFloatTextureSupport(&mSupportsFloatLinearFilter, &mSupportsFloatRenderableTextures);
+ mSupportsHalfFloatTextures = display->getHalfFloatTextureSupport(&mSupportsHalfFloatLinearFilter, &mSupportsHalfFloatRenderableTextures);
+ mSupportsLuminanceTextures = display->getLuminanceTextureSupport();
+ mSupportsLuminanceAlphaTextures = display->getLuminanceAlphaTextureSupport();
+
+ mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16);
+
+ initExtensionString();
+
+ mState.viewportX = 0;
+ mState.viewportY = 0;
+ mState.viewportWidth = surface->getWidth();
+ mState.viewportHeight = surface->getHeight();
+
+ mState.scissorX = 0;
+ mState.scissorY = 0;
+ mState.scissorWidth = surface->getWidth();
+ mState.scissorHeight = surface->getHeight();
+
+ mHasBeenCurrent = true;
+ }
+
+ // Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names
+ IDirect3DSurface9 *defaultRenderTarget = surface->getRenderTarget();
+ IDirect3DSurface9 *depthStencil = surface->getDepthStencil();
+
+ Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget);
+ DepthStencilbuffer *depthStencilbufferZero = new DepthStencilbuffer(depthStencil);
+ Framebuffer *framebufferZero = new DefaultFramebuffer(colorbufferZero, depthStencilbufferZero);
+
+ setFramebufferZero(framebufferZero);
+
+ if (defaultRenderTarget)
+ {
+ defaultRenderTarget->Release();
+ }
+
+ if (depthStencil)
+ {
+ depthStencil->Release();
+ }
+
+ markAllStateDirty();
+}
+
+// This function will set all of the state-related dirty flags, so that all state is set during next pre-draw.
+void Context::markAllStateDirty()
+{
+ for (int t = 0; t < MAX_TEXTURE_IMAGE_UNITS; t++)
+ {
+ mAppliedTextureSerialPS[t] = 0;
+ }
+
+ for (int t = 0; t < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; t++)
+ {
+ mAppliedTextureSerialVS[t] = 0;
+ }
+
+ mAppliedProgramSerial = 0;
+ mAppliedRenderTargetSerial = 0;
+ mAppliedDepthbufferSerial = 0;
+ mAppliedStencilbufferSerial = 0;
+ mDepthStencilInitialized = false;
+
+ mClearStateDirty = true;
+ mCullStateDirty = true;
+ mDepthStateDirty = true;
+ mMaskStateDirty = true;
+ mBlendStateDirty = true;
+ mStencilStateDirty = true;
+ mPolygonOffsetStateDirty = true;
+ mScissorStateDirty = true;
+ mSampleStateDirty = true;
+ mDitherStateDirty = true;
+ mFrontFaceDirty = true;
+}
+
+void Context::setClearColor(float red, float green, float blue, float alpha)
+{
+ mState.colorClearValue.red = red;
+ mState.colorClearValue.green = green;
+ mState.colorClearValue.blue = blue;
+ mState.colorClearValue.alpha = alpha;
+}
+
+void Context::setClearDepth(float depth)
+{
+ mState.depthClearValue = depth;
+}
+
+void Context::setClearStencil(int stencil)
+{
+ mState.stencilClearValue = stencil;
+}
+
+void Context::setCullFace(bool enabled)
+{
+ if (mState.cullFace != enabled)
+ {
+ mState.cullFace = enabled;
+ mCullStateDirty = true;
+ }
+}
+
+bool Context::isCullFaceEnabled() const
+{
+ return mState.cullFace;
+}
+
+void Context::setCullMode(GLenum mode)
+{
+ if (mState.cullMode != mode)
+ {
+ mState.cullMode = mode;
+ mCullStateDirty = true;
+ }
+}
+
+void Context::setFrontFace(GLenum front)
+{
+ if (mState.frontFace != front)
+ {
+ mState.frontFace = front;
+ mFrontFaceDirty = true;
+ }
+}
+
+void Context::setDepthTest(bool enabled)
+{
+ if (mState.depthTest != enabled)
+ {
+ mState.depthTest = enabled;
+ mDepthStateDirty = true;
+ }
+}
+
+bool Context::isDepthTestEnabled() const
+{
+ return mState.depthTest;
+}
+
+void Context::setDepthFunc(GLenum depthFunc)
+{
+ if (mState.depthFunc != depthFunc)
+ {
+ mState.depthFunc = depthFunc;
+ mDepthStateDirty = true;
+ }
+}
+
+void Context::setDepthRange(float zNear, float zFar)
+{
+ mState.zNear = zNear;
+ mState.zFar = zFar;
+}
+
+void Context::setBlend(bool enabled)
+{
+ if (mState.blend != enabled)
+ {
+ mState.blend = enabled;
+ mBlendStateDirty = true;
+ }
+}
+
+bool Context::isBlendEnabled() const
+{
+ return mState.blend;
+}
+
+void Context::setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha)
+{
+ if (mState.sourceBlendRGB != sourceRGB ||
+ mState.sourceBlendAlpha != sourceAlpha ||
+ mState.destBlendRGB != destRGB ||
+ mState.destBlendAlpha != destAlpha)
+ {
+ mState.sourceBlendRGB = sourceRGB;
+ mState.destBlendRGB = destRGB;
+ mState.sourceBlendAlpha = sourceAlpha;
+ mState.destBlendAlpha = destAlpha;
+ mBlendStateDirty = true;
+ }
+}
+
+void Context::setBlendColor(float red, float green, float blue, float alpha)
+{
+ if (mState.blendColor.red != red ||
+ mState.blendColor.green != green ||
+ mState.blendColor.blue != blue ||
+ mState.blendColor.alpha != alpha)
+ {
+ mState.blendColor.red = red;
+ mState.blendColor.green = green;
+ mState.blendColor.blue = blue;
+ mState.blendColor.alpha = alpha;
+ mBlendStateDirty = true;
+ }
+}
+
+void Context::setBlendEquation(GLenum rgbEquation, GLenum alphaEquation)
+{
+ if (mState.blendEquationRGB != rgbEquation ||
+ mState.blendEquationAlpha != alphaEquation)
+ {
+ mState.blendEquationRGB = rgbEquation;
+ mState.blendEquationAlpha = alphaEquation;
+ mBlendStateDirty = true;
+ }
+}
+
+void Context::setStencilTest(bool enabled)
+{
+ if (mState.stencilTest != enabled)
+ {
+ mState.stencilTest = enabled;
+ mStencilStateDirty = true;
+ }
+}
+
+bool Context::isStencilTestEnabled() const
+{
+ return mState.stencilTest;
+}
+
+void Context::setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask)
+{
+ if (mState.stencilFunc != stencilFunc ||
+ mState.stencilRef != stencilRef ||
+ mState.stencilMask != stencilMask)
+ {
+ mState.stencilFunc = stencilFunc;
+ mState.stencilRef = (stencilRef > 0) ? stencilRef : 0;
+ mState.stencilMask = stencilMask;
+ mStencilStateDirty = true;
+ }
+}
+
+void Context::setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask)
+{
+ if (mState.stencilBackFunc != stencilBackFunc ||
+ mState.stencilBackRef != stencilBackRef ||
+ mState.stencilBackMask != stencilBackMask)
+ {
+ mState.stencilBackFunc = stencilBackFunc;
+ mState.stencilBackRef = (stencilBackRef > 0) ? stencilBackRef : 0;
+ mState.stencilBackMask = stencilBackMask;
+ mStencilStateDirty = true;
+ }
+}
+
+void Context::setStencilWritemask(GLuint stencilWritemask)
+{
+ if (mState.stencilWritemask != stencilWritemask)
+ {
+ mState.stencilWritemask = stencilWritemask;
+ mStencilStateDirty = true;
+ }
+}
+
+void Context::setStencilBackWritemask(GLuint stencilBackWritemask)
+{
+ if (mState.stencilBackWritemask != stencilBackWritemask)
+ {
+ mState.stencilBackWritemask = stencilBackWritemask;
+ mStencilStateDirty = true;
+ }
+}
+
+void Context::setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass)
+{
+ if (mState.stencilFail != stencilFail ||
+ mState.stencilPassDepthFail != stencilPassDepthFail ||
+ mState.stencilPassDepthPass != stencilPassDepthPass)
+ {
+ mState.stencilFail = stencilFail;
+ mState.stencilPassDepthFail = stencilPassDepthFail;
+ mState.stencilPassDepthPass = stencilPassDepthPass;
+ mStencilStateDirty = true;
+ }
+}
+
+void Context::setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass)
+{
+ if (mState.stencilBackFail != stencilBackFail ||
+ mState.stencilBackPassDepthFail != stencilBackPassDepthFail ||
+ mState.stencilBackPassDepthPass != stencilBackPassDepthPass)
+ {
+ mState.stencilBackFail = stencilBackFail;
+ mState.stencilBackPassDepthFail = stencilBackPassDepthFail;
+ mState.stencilBackPassDepthPass = stencilBackPassDepthPass;
+ mStencilStateDirty = true;
+ }
+}
+
+void Context::setPolygonOffsetFill(bool enabled)
+{
+ if (mState.polygonOffsetFill != enabled)
+ {
+ mState.polygonOffsetFill = enabled;
+ mPolygonOffsetStateDirty = true;
+ }
+}
+
+bool Context::isPolygonOffsetFillEnabled() const
+{
+ return mState.polygonOffsetFill;
+
+}
+
+void Context::setPolygonOffsetParams(GLfloat factor, GLfloat units)
+{
+ if (mState.polygonOffsetFactor != factor ||
+ mState.polygonOffsetUnits != units)
+ {
+ mState.polygonOffsetFactor = factor;
+ mState.polygonOffsetUnits = units;
+ mPolygonOffsetStateDirty = true;
+ }
+}
+
+void Context::setSampleAlphaToCoverage(bool enabled)
+{
+ if (mState.sampleAlphaToCoverage != enabled)
+ {
+ mState.sampleAlphaToCoverage = enabled;
+ mSampleStateDirty = true;
+ }
+}
+
+bool Context::isSampleAlphaToCoverageEnabled() const
+{
+ return mState.sampleAlphaToCoverage;
+}
+
+void Context::setSampleCoverage(bool enabled)
+{
+ if (mState.sampleCoverage != enabled)
+ {
+ mState.sampleCoverage = enabled;
+ mSampleStateDirty = true;
+ }
+}
+
+bool Context::isSampleCoverageEnabled() const
+{
+ return mState.sampleCoverage;
+}
+
+void Context::setSampleCoverageParams(GLclampf value, bool invert)
+{
+ if (mState.sampleCoverageValue != value ||
+ mState.sampleCoverageInvert != invert)
+ {
+ mState.sampleCoverageValue = value;
+ mState.sampleCoverageInvert = invert;
+ mSampleStateDirty = true;
+ }
+}
+
+void Context::setScissorTest(bool enabled)
+{
+ if (mState.scissorTest != enabled)
+ {
+ mState.scissorTest = enabled;
+ mScissorStateDirty = true;
+ }
+}
+
+bool Context::isScissorTestEnabled() const
+{
+ return mState.scissorTest;
+}
+
+void Context::setDither(bool enabled)
+{
+ if (mState.dither != enabled)
+ {
+ mState.dither = enabled;
+ mDitherStateDirty = true;
+ }
+}
+
+bool Context::isDitherEnabled() const
+{
+ return mState.dither;
+}
+
+void Context::setLineWidth(GLfloat width)
+{
+ mState.lineWidth = width;
+}
+
+void Context::setGenerateMipmapHint(GLenum hint)
+{
+ mState.generateMipmapHint = hint;
+}
+
+void Context::setFragmentShaderDerivativeHint(GLenum hint)
+{
+ mState.fragmentShaderDerivativeHint = hint;
+ // TODO: Propagate the hint to shader translator so we can write
+ // ddx, ddx_coarse, or ddx_fine depending on the hint.
+ // Ignore for now. It is valid for implementations to ignore hint.
+}
+
+void Context::setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ mState.viewportX = x;
+ mState.viewportY = y;
+ mState.viewportWidth = width;
+ mState.viewportHeight = height;
+}
+
+void Context::setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ if (mState.scissorX != x || mState.scissorY != y ||
+ mState.scissorWidth != width || mState.scissorHeight != height)
+ {
+ mState.scissorX = x;
+ mState.scissorY = y;
+ mState.scissorWidth = width;
+ mState.scissorHeight = height;
+ mScissorStateDirty = true;
+ }
+}
+
+void Context::setColorMask(bool red, bool green, bool blue, bool alpha)
+{
+ if (mState.colorMaskRed != red || mState.colorMaskGreen != green ||
+ mState.colorMaskBlue != blue || mState.colorMaskAlpha != alpha)
+ {
+ mState.colorMaskRed = red;
+ mState.colorMaskGreen = green;
+ mState.colorMaskBlue = blue;
+ mState.colorMaskAlpha = alpha;
+ mMaskStateDirty = true;
+ }
+}
+
+void Context::setDepthMask(bool mask)
+{
+ if (mState.depthMask != mask)
+ {
+ mState.depthMask = mask;
+ mMaskStateDirty = true;
+ }
+}
+
+void Context::setActiveSampler(unsigned int active)
+{
+ mState.activeSampler = active;
+}
+
+GLuint Context::getReadFramebufferHandle() const
+{
+ return mState.readFramebuffer;
+}
+
+GLuint Context::getDrawFramebufferHandle() const
+{
+ return mState.drawFramebuffer;
+}
+
+GLuint Context::getRenderbufferHandle() const
+{
+ return mState.renderbuffer.id();
+}
+
+GLuint Context::getArrayBufferHandle() const
+{
+ return mState.arrayBuffer.id();
+}
+
+void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
+{
+ mState.vertexAttribute[attribNum].mArrayEnabled = enabled;
+}
+
+const VertexAttribute &Context::getVertexAttribState(unsigned int attribNum)
+{
+ return mState.vertexAttribute[attribNum];
+}
+
+void Context::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized,
+ GLsizei stride, const void *pointer)
+{
+ mState.vertexAttribute[attribNum].mBoundBuffer.set(boundBuffer);
+ mState.vertexAttribute[attribNum].mSize = size;
+ mState.vertexAttribute[attribNum].mType = type;
+ mState.vertexAttribute[attribNum].mNormalized = normalized;
+ mState.vertexAttribute[attribNum].mStride = stride;
+ mState.vertexAttribute[attribNum].mPointer = pointer;
+}
+
+const void *Context::getVertexAttribPointer(unsigned int attribNum) const
+{
+ return mState.vertexAttribute[attribNum].mPointer;
+}
+
+const VertexAttributeArray &Context::getVertexAttributes()
+{
+ return mState.vertexAttribute;
+}
+
+void Context::setPackAlignment(GLint alignment)
+{
+ mState.packAlignment = alignment;
+}
+
+GLint Context::getPackAlignment() const
+{
+ return mState.packAlignment;
+}
+
+void Context::setUnpackAlignment(GLint alignment)
+{
+ mState.unpackAlignment = alignment;
+}
+
+GLint Context::getUnpackAlignment() const
+{
+ return mState.unpackAlignment;
+}
+
+GLuint Context::createBuffer()
+{
+ return mResourceManager->createBuffer();
+}
+
+GLuint Context::createProgram()
+{
+ return mResourceManager->createProgram();
+}
+
+GLuint Context::createShader(GLenum type)
+{
+ return mResourceManager->createShader(type);
+}
+
+GLuint Context::createTexture()
+{
+ return mResourceManager->createTexture();
+}
+
+GLuint Context::createRenderbuffer()
+{
+ return mResourceManager->createRenderbuffer();
+}
+
+// Returns an unused framebuffer name
+GLuint Context::createFramebuffer()
+{
+ GLuint handle = mFramebufferHandleAllocator.allocate();
+
+ mFramebufferMap[handle] = NULL;
+
+ return handle;
+}
+
+GLuint Context::createFence()
+{
+ GLuint handle = mFenceHandleAllocator.allocate();
+
+ mFenceMap[handle] = new Fence;
+
+ return handle;
+}
+
+void Context::deleteBuffer(GLuint buffer)
+{
+ if (mResourceManager->getBuffer(buffer))
+ {
+ detachBuffer(buffer);
+ }
+
+ mResourceManager->deleteBuffer(buffer);
+}
+
+void Context::deleteShader(GLuint shader)
+{
+ mResourceManager->deleteShader(shader);
+}
+
+void Context::deleteProgram(GLuint program)
+{
+ mResourceManager->deleteProgram(program);
+}
+
+void Context::deleteTexture(GLuint texture)
+{
+ if (mResourceManager->getTexture(texture))
+ {
+ detachTexture(texture);
+ }
+
+ mResourceManager->deleteTexture(texture);
+}
+
+void Context::deleteRenderbuffer(GLuint renderbuffer)
+{
+ if (mResourceManager->getRenderbuffer(renderbuffer))
+ {
+ detachRenderbuffer(renderbuffer);
+ }
+
+ mResourceManager->deleteRenderbuffer(renderbuffer);
+}
+
+void Context::deleteFramebuffer(GLuint framebuffer)
+{
+ FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer);
+
+ if (framebufferObject != mFramebufferMap.end())
+ {
+ detachFramebuffer(framebuffer);
+
+ mFramebufferHandleAllocator.release(framebufferObject->first);
+ delete framebufferObject->second;
+ mFramebufferMap.erase(framebufferObject);
+ }
+}
+
+void Context::deleteFence(GLuint fence)
+{
+ FenceMap::iterator fenceObject = mFenceMap.find(fence);
+
+ if (fenceObject != mFenceMap.end())
+ {
+ mFenceHandleAllocator.release(fenceObject->first);
+ delete fenceObject->second;
+ mFenceMap.erase(fenceObject);
+ }
+}
+
+Buffer *Context::getBuffer(GLuint handle)
+{
+ return mResourceManager->getBuffer(handle);
+}
+
+Shader *Context::getShader(GLuint handle)
+{
+ return mResourceManager->getShader(handle);
+}
+
+Program *Context::getProgram(GLuint handle)
+{
+ return mResourceManager->getProgram(handle);
+}
+
+Texture *Context::getTexture(GLuint handle)
+{
+ return mResourceManager->getTexture(handle);
+}
+
+Renderbuffer *Context::getRenderbuffer(GLuint handle)
+{
+ return mResourceManager->getRenderbuffer(handle);
+}
+
+Framebuffer *Context::getReadFramebuffer()
+{
+ return getFramebuffer(mState.readFramebuffer);
+}
+
+Framebuffer *Context::getDrawFramebuffer()
+{
+ return getFramebuffer(mState.drawFramebuffer);
+}
+
+void Context::bindArrayBuffer(unsigned int buffer)
+{
+ mResourceManager->checkBufferAllocation(buffer);
+
+ mState.arrayBuffer.set(getBuffer(buffer));
+}
+
+void Context::bindElementArrayBuffer(unsigned int buffer)
+{
+ mResourceManager->checkBufferAllocation(buffer);
+
+ mState.elementArrayBuffer.set(getBuffer(buffer));
+}
+
+void Context::bindTexture2D(GLuint texture)
+{
+ mResourceManager->checkTextureAllocation(texture, TEXTURE_2D);
+
+ mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture));
+}
+
+void Context::bindTextureCubeMap(GLuint texture)
+{
+ mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE);
+
+ mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture));
+}
+
+void Context::bindReadFramebuffer(GLuint framebuffer)
+{
+ if (!getFramebuffer(framebuffer))
+ {
+ mFramebufferMap[framebuffer] = new Framebuffer();
+ }
+
+ mState.readFramebuffer = framebuffer;
+}
+
+void Context::bindDrawFramebuffer(GLuint framebuffer)
+{
+ if (!getFramebuffer(framebuffer))
+ {
+ mFramebufferMap[framebuffer] = new Framebuffer();
+ }
+
+ mState.drawFramebuffer = framebuffer;
+}
+
+void Context::bindRenderbuffer(GLuint renderbuffer)
+{
+ mResourceManager->checkRenderbufferAllocation(renderbuffer);
+
+ mState.renderbuffer.set(getRenderbuffer(renderbuffer));
+}
+
+void Context::useProgram(GLuint program)
+{
+ GLuint priorProgram = mState.currentProgram;
+ mState.currentProgram = program; // Must switch before trying to delete, otherwise it only gets flagged.
+
+ if (priorProgram != program)
+ {
+ Program *newProgram = mResourceManager->getProgram(program);
+ Program *oldProgram = mResourceManager->getProgram(priorProgram);
+
+ if (newProgram)
+ {
+ newProgram->addRef();
+ }
+
+ if (oldProgram)
+ {
+ oldProgram->release();
+ }
+ }
+}
+
+void Context::setFramebufferZero(Framebuffer *buffer)
+{
+ delete mFramebufferMap[0];
+ mFramebufferMap[0] = buffer;
+}
+
+void Context::setRenderbufferStorage(RenderbufferStorage *renderbuffer)
+{
+ Renderbuffer *renderbufferObject = mState.renderbuffer.get();
+ renderbufferObject->setStorage(renderbuffer);
+}
+
+Framebuffer *Context::getFramebuffer(unsigned int handle)
+{
+ FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle);
+
+ if (framebuffer == mFramebufferMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return framebuffer->second;
+ }
+}
+
+Fence *Context::getFence(unsigned int handle)
+{
+ FenceMap::iterator fence = mFenceMap.find(handle);
+
+ if (fence == mFenceMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return fence->second;
+ }
+}
+
+Buffer *Context::getArrayBuffer()
+{
+ return mState.arrayBuffer.get();
+}
+
+Buffer *Context::getElementArrayBuffer()
+{
+ return mState.elementArrayBuffer.get();
+}
+
+Program *Context::getCurrentProgram()
+{
+ return mResourceManager->getProgram(mState.currentProgram);
+}
+
+Texture2D *Context::getTexture2D()
+{
+ return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D));
+}
+
+TextureCubeMap *Context::getTextureCubeMap()
+{
+ return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE));
+}
+
+Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type)
+{
+ GLuint texid = mState.samplerTexture[type][sampler].id();
+
+ if (texid == 0) // Special case: 0 refers to different initial textures based on the target
+ {
+ switch (type)
+ {
+ default: UNREACHABLE();
+ case TEXTURE_2D: return mTexture2DZero.get();
+ case TEXTURE_CUBE: return mTextureCubeMapZero.get();
+ }
+ }
+
+ return mState.samplerTexture[type][sampler].get();
+}
+
+bool Context::getBooleanv(GLenum pname, GLboolean *params)
+{
+ switch (pname)
+ {
+ case GL_SHADER_COMPILER: *params = GL_TRUE; break;
+ case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break;
+ case GL_DEPTH_WRITEMASK: *params = mState.depthMask; break;
+ case GL_COLOR_WRITEMASK:
+ params[0] = mState.colorMaskRed;
+ params[1] = mState.colorMaskGreen;
+ params[2] = mState.colorMaskBlue;
+ params[3] = mState.colorMaskAlpha;
+ break;
+ case GL_CULL_FACE: *params = mState.cullFace; break;
+ case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break;
+ case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break;
+ case GL_SCISSOR_TEST: *params = mState.scissorTest; break;
+ case GL_STENCIL_TEST: *params = mState.stencilTest; break;
+ case GL_DEPTH_TEST: *params = mState.depthTest; break;
+ case GL_BLEND: *params = mState.blend; break;
+ case GL_DITHER: *params = mState.dither; break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool Context::getFloatv(GLenum pname, GLfloat *params)
+{
+ // Please note: DEPTH_CLEAR_VALUE is included in our internal getFloatv implementation
+ // because it is stored as a float, despite the fact that the GL ES 2.0 spec names
+ // GetIntegerv as its native query function. As it would require conversion in any
+ // case, this should make no difference to the calling application.
+ switch (pname)
+ {
+ case GL_LINE_WIDTH: *params = mState.lineWidth; break;
+ case GL_SAMPLE_COVERAGE_VALUE: *params = mState.sampleCoverageValue; break;
+ case GL_DEPTH_CLEAR_VALUE: *params = mState.depthClearValue; break;
+ case GL_POLYGON_OFFSET_FACTOR: *params = mState.polygonOffsetFactor; break;
+ case GL_POLYGON_OFFSET_UNITS: *params = mState.polygonOffsetUnits; break;
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ params[0] = gl::ALIASED_LINE_WIDTH_RANGE_MIN;
+ params[1] = gl::ALIASED_LINE_WIDTH_RANGE_MAX;
+ break;
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ params[0] = gl::ALIASED_POINT_SIZE_RANGE_MIN;
+ params[1] = supportsShaderModel3() ? gl::ALIASED_POINT_SIZE_RANGE_MAX_SM3 : gl::ALIASED_POINT_SIZE_RANGE_MAX_SM2;
+ break;
+ case GL_DEPTH_RANGE:
+ params[0] = mState.zNear;
+ params[1] = mState.zFar;
+ break;
+ case GL_COLOR_CLEAR_VALUE:
+ params[0] = mState.colorClearValue.red;
+ params[1] = mState.colorClearValue.green;
+ params[2] = mState.colorClearValue.blue;
+ params[3] = mState.colorClearValue.alpha;
+ break;
+ case GL_BLEND_COLOR:
+ params[0] = mState.blendColor.red;
+ params[1] = mState.blendColor.green;
+ params[2] = mState.blendColor.blue;
+ params[3] = mState.blendColor.alpha;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool Context::getIntegerv(GLenum pname, GLint *params)
+{
+ // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation
+ // because it is stored as a float, despite the fact that the GL ES 2.0 spec names
+ // GetIntegerv as its native query function. As it would require conversion in any
+ // case, this should make no difference to the calling application. You may find it in
+ // Context::getFloatv.
+ switch (pname)
+ {
+ case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break;
+ case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = gl::MAX_VERTEX_UNIFORM_VECTORS; break;
+ case GL_MAX_VARYING_VECTORS: *params = getMaximumVaryingVectors(); break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = getMaximumCombinedTextureImageUnits(); break;
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = getMaximumVertexTextureImageUnits(); break;
+ case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break;
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = getMaximumFragmentUniformVectors(); break;
+ case GL_MAX_RENDERBUFFER_SIZE: *params = getMaximumRenderbufferDimension(); break;
+ case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break;
+ case GL_SHADER_BINARY_FORMATS: /* no shader binary formats are supported */ break;
+ case GL_ARRAY_BUFFER_BINDING: *params = mState.arrayBuffer.id(); break;
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING: *params = mState.elementArrayBuffer.id(); break;
+ //case GL_FRAMEBUFFER_BINDING: // now equivalent to GL_DRAW_FRAMEBUFFER_BINDING_ANGLE
+ case GL_DRAW_FRAMEBUFFER_BINDING_ANGLE: *params = mState.drawFramebuffer; break;
+ case GL_READ_FRAMEBUFFER_BINDING_ANGLE: *params = mState.readFramebuffer; break;
+ case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer.id(); break;
+ case GL_CURRENT_PROGRAM: *params = mState.currentProgram; break;
+ case GL_PACK_ALIGNMENT: *params = mState.packAlignment; break;
+ case GL_UNPACK_ALIGNMENT: *params = mState.unpackAlignment; break;
+ case GL_GENERATE_MIPMAP_HINT: *params = mState.generateMipmapHint; break;
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break;
+ case GL_ACTIVE_TEXTURE: *params = (mState.activeSampler + GL_TEXTURE0); break;
+ case GL_STENCIL_FUNC: *params = mState.stencilFunc; break;
+ case GL_STENCIL_REF: *params = mState.stencilRef; break;
+ case GL_STENCIL_VALUE_MASK: *params = mState.stencilMask; break;
+ case GL_STENCIL_BACK_FUNC: *params = mState.stencilBackFunc; break;
+ case GL_STENCIL_BACK_REF: *params = mState.stencilBackRef; break;
+ case GL_STENCIL_BACK_VALUE_MASK: *params = mState.stencilBackMask; break;
+ case GL_STENCIL_FAIL: *params = mState.stencilFail; break;
+ case GL_STENCIL_PASS_DEPTH_FAIL: *params = mState.stencilPassDepthFail; break;
+ case GL_STENCIL_PASS_DEPTH_PASS: *params = mState.stencilPassDepthPass; break;
+ case GL_STENCIL_BACK_FAIL: *params = mState.stencilBackFail; break;
+ case GL_STENCIL_BACK_PASS_DEPTH_FAIL: *params = mState.stencilBackPassDepthFail; break;
+ case GL_STENCIL_BACK_PASS_DEPTH_PASS: *params = mState.stencilBackPassDepthPass; break;
+ case GL_DEPTH_FUNC: *params = mState.depthFunc; break;
+ case GL_BLEND_SRC_RGB: *params = mState.sourceBlendRGB; break;
+ case GL_BLEND_SRC_ALPHA: *params = mState.sourceBlendAlpha; break;
+ case GL_BLEND_DST_RGB: *params = mState.destBlendRGB; break;
+ case GL_BLEND_DST_ALPHA: *params = mState.destBlendAlpha; break;
+ case GL_BLEND_EQUATION_RGB: *params = mState.blendEquationRGB; break;
+ case GL_BLEND_EQUATION_ALPHA: *params = mState.blendEquationAlpha; break;
+ case GL_STENCIL_WRITEMASK: *params = mState.stencilWritemask; break;
+ case GL_STENCIL_BACK_WRITEMASK: *params = mState.stencilBackWritemask; break;
+ case GL_STENCIL_CLEAR_VALUE: *params = mState.stencilClearValue; break;
+ case GL_SUBPIXEL_BITS: *params = 4; break;
+ case GL_MAX_TEXTURE_SIZE: *params = getMaximumTextureDimension(); break;
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = getMaximumCubeTextureDimension(); break;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ {
+ if (supportsCompressedTextures())
+ {
+ // at current, only GL_COMPRESSED_RGB_S3TC_DXT1_EXT and
+ // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT are supported
+ *params = 2;
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_MAX_SAMPLES_ANGLE:
+ {
+ GLsizei maxSamples = getMaxSupportedSamples();
+ if (maxSamples != 0)
+ {
+ *params = maxSamples;
+ }
+ else
+ {
+ return false;
+ }
+
+ break;
+ }
+ case GL_SAMPLE_BUFFERS:
+ case GL_SAMPLES:
+ {
+ gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ if (framebuffer->completeness() == GL_FRAMEBUFFER_COMPLETE)
+ {
+ switch (pname)
+ {
+ case GL_SAMPLE_BUFFERS:
+ if (framebuffer->getSamples() != 0)
+ {
+ *params = 1;
+ }
+ else
+ {
+ *params = 0;
+ }
+ break;
+ case GL_SAMPLES:
+ *params = framebuffer->getSamples();
+ break;
+ }
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE: *params = gl::IMPLEMENTATION_COLOR_READ_TYPE; break;
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT: *params = gl::IMPLEMENTATION_COLOR_READ_FORMAT; break;
+ case GL_MAX_VIEWPORT_DIMS:
+ {
+ int maxDimension = std::max(getMaximumRenderbufferDimension(), getMaximumTextureDimension());
+ params[0] = maxDimension;
+ params[1] = maxDimension;
+ }
+ break;
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ {
+ if (supportsCompressedTextures())
+ {
+ params[0] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ params[1] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ }
+ }
+ break;
+ case GL_VIEWPORT:
+ params[0] = mState.viewportX;
+ params[1] = mState.viewportY;
+ params[2] = mState.viewportWidth;
+ params[3] = mState.viewportHeight;
+ break;
+ case GL_SCISSOR_BOX:
+ params[0] = mState.scissorX;
+ params[1] = mState.scissorY;
+ params[2] = mState.scissorWidth;
+ params[3] = mState.scissorHeight;
+ break;
+ case GL_CULL_FACE_MODE: *params = mState.cullMode; break;
+ case GL_FRONT_FACE: *params = mState.frontFace; break;
+ case GL_RED_BITS:
+ case GL_GREEN_BITS:
+ case GL_BLUE_BITS:
+ case GL_ALPHA_BITS:
+ {
+ gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ gl::Colorbuffer *colorbuffer = framebuffer->getColorbuffer();
+
+ if (colorbuffer)
+ {
+ switch (pname)
+ {
+ case GL_RED_BITS: *params = colorbuffer->getRedSize(); break;
+ case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break;
+ case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break;
+ case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break;
+ }
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_DEPTH_BITS:
+ {
+ gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ gl::DepthStencilbuffer *depthbuffer = framebuffer->getDepthbuffer();
+
+ if (depthbuffer)
+ {
+ *params = depthbuffer->getDepthSize();
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_STENCIL_BITS:
+ {
+ gl::Framebuffer *framebuffer = getDrawFramebuffer();
+ gl::DepthStencilbuffer *stencilbuffer = framebuffer->getStencilbuffer();
+
+ if (stencilbuffer)
+ {
+ *params = stencilbuffer->getStencilSize();
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ break;
+ case GL_TEXTURE_BINDING_2D:
+ {
+ if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1)
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id();
+ }
+ break;
+ case GL_TEXTURE_BINDING_CUBE_MAP:
+ {
+ if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1)
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id();
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams)
+{
+ // Please note: the query type returned for DEPTH_CLEAR_VALUE in this implementation
+ // is FLOAT rather than INT, as would be suggested by the GL ES 2.0 spec. This is due
+ // to the fact that it is stored internally as a float, and so would require conversion
+ // if returned from Context::getIntegerv. Since this conversion is already implemented
+ // in the case that one calls glGetIntegerv to retrieve a float-typed state variable, we
+ // place DEPTH_CLEAR_VALUE with the floats. This should make no difference to the calling
+ // application.
+ switch (pname)
+ {
+ case GL_COMPRESSED_TEXTURE_FORMATS: /* no compressed texture formats are supported */
+ case GL_SHADER_BINARY_FORMATS:
+ {
+ *type = GL_INT;
+ *numParams = 0;
+ }
+ break;
+ case GL_MAX_VERTEX_ATTRIBS:
+ case GL_MAX_VERTEX_UNIFORM_VECTORS:
+ case GL_MAX_VARYING_VECTORS:
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+ case GL_MAX_TEXTURE_IMAGE_UNITS:
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+ case GL_MAX_RENDERBUFFER_SIZE:
+ case GL_NUM_SHADER_BINARY_FORMATS:
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ case GL_ARRAY_BUFFER_BINDING:
+ case GL_FRAMEBUFFER_BINDING:
+ case GL_RENDERBUFFER_BINDING:
+ case GL_CURRENT_PROGRAM:
+ case GL_PACK_ALIGNMENT:
+ case GL_UNPACK_ALIGNMENT:
+ case GL_GENERATE_MIPMAP_HINT:
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+ case GL_RED_BITS:
+ case GL_GREEN_BITS:
+ case GL_BLUE_BITS:
+ case GL_ALPHA_BITS:
+ case GL_DEPTH_BITS:
+ case GL_STENCIL_BITS:
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+ case GL_CULL_FACE_MODE:
+ case GL_FRONT_FACE:
+ case GL_ACTIVE_TEXTURE:
+ case GL_STENCIL_FUNC:
+ case GL_STENCIL_VALUE_MASK:
+ case GL_STENCIL_REF:
+ case GL_STENCIL_FAIL:
+ case GL_STENCIL_PASS_DEPTH_FAIL:
+ case GL_STENCIL_PASS_DEPTH_PASS:
+ case GL_STENCIL_BACK_FUNC:
+ case GL_STENCIL_BACK_VALUE_MASK:
+ case GL_STENCIL_BACK_REF:
+ case GL_STENCIL_BACK_FAIL:
+ case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
+ case GL_STENCIL_BACK_PASS_DEPTH_PASS:
+ case GL_DEPTH_FUNC:
+ case GL_BLEND_SRC_RGB:
+ case GL_BLEND_SRC_ALPHA:
+ case GL_BLEND_DST_RGB:
+ case GL_BLEND_DST_ALPHA:
+ case GL_BLEND_EQUATION_RGB:
+ case GL_BLEND_EQUATION_ALPHA:
+ case GL_STENCIL_WRITEMASK:
+ case GL_STENCIL_BACK_WRITEMASK:
+ case GL_STENCIL_CLEAR_VALUE:
+ case GL_SUBPIXEL_BITS:
+ case GL_MAX_TEXTURE_SIZE:
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
+ case GL_SAMPLE_BUFFERS:
+ case GL_SAMPLES:
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE:
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
+ case GL_TEXTURE_BINDING_2D:
+ case GL_TEXTURE_BINDING_CUBE_MAP:
+ {
+ *type = GL_INT;
+ *numParams = 1;
+ }
+ break;
+ case GL_MAX_SAMPLES_ANGLE:
+ {
+ if (getMaxSupportedSamples() != 0)
+ {
+ *type = GL_INT;
+ *numParams = 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ break;
+ case GL_MAX_VIEWPORT_DIMS:
+ {
+ *type = GL_INT;
+ *numParams = 2;
+ }
+ break;
+ case GL_VIEWPORT:
+ case GL_SCISSOR_BOX:
+ {
+ *type = GL_INT;
+ *numParams = 4;
+ }
+ break;
+ case GL_SHADER_COMPILER:
+ case GL_SAMPLE_COVERAGE_INVERT:
+ case GL_DEPTH_WRITEMASK:
+ case GL_CULL_FACE: // CULL_FACE through DITHER are natural to IsEnabled,
+ case GL_POLYGON_OFFSET_FILL: // but can be retrieved through the Get{Type}v queries.
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: // For this purpose, they are treated here as bool-natural
+ case GL_SAMPLE_COVERAGE:
+ case GL_SCISSOR_TEST:
+ case GL_STENCIL_TEST:
+ case GL_DEPTH_TEST:
+ case GL_BLEND:
+ case GL_DITHER:
+ {
+ *type = GL_BOOL;
+ *numParams = 1;
+ }
+ break;
+ case GL_COLOR_WRITEMASK:
+ {
+ *type = GL_BOOL;
+ *numParams = 4;
+ }
+ break;
+ case GL_POLYGON_OFFSET_FACTOR:
+ case GL_POLYGON_OFFSET_UNITS:
+ case GL_SAMPLE_COVERAGE_VALUE:
+ case GL_DEPTH_CLEAR_VALUE:
+ case GL_LINE_WIDTH:
+ {
+ *type = GL_FLOAT;
+ *numParams = 1;
+ }
+ break;
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ case GL_DEPTH_RANGE:
+ {
+ *type = GL_FLOAT;
+ *numParams = 2;
+ }
+ break;
+ case GL_COLOR_CLEAR_VALUE:
+ case GL_BLEND_COLOR:
+ {
+ *type = GL_FLOAT;
+ *numParams = 4;
+ }
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+// Applies the render target surface, depth stencil surface, viewport rectangle and
+// scissor rectangle to the Direct3D 9 device
+bool Context::applyRenderTarget(bool ignoreViewport)
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ Framebuffer *framebufferObject = getDrawFramebuffer();
+
+ if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
+ }
+
+ IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ return false; // Context must be lost
+ }
+
+ IDirect3DSurface9 *depthStencil = NULL;
+
+ unsigned int renderTargetSerial = framebufferObject->getRenderTargetSerial();
+ if (renderTargetSerial != mAppliedRenderTargetSerial)
+ {
+ device->SetRenderTarget(0, renderTarget);
+ mAppliedRenderTargetSerial = renderTargetSerial;
+ mScissorStateDirty = true; // Scissor area must be clamped to render target's size-- this is different for different render targets.
+ }
+
+ unsigned int depthbufferSerial = 0;
+ unsigned int stencilbufferSerial = 0;
+ if (framebufferObject->getDepthbufferType() != GL_NONE)
+ {
+ depthStencil = framebufferObject->getDepthbuffer()->getDepthStencil();
+ if (!depthStencil)
+ {
+ ERR("Depth stencil pointer unexpectedly null.");
+ return false;
+ }
+
+ depthbufferSerial = framebufferObject->getDepthbuffer()->getSerial();
+ }
+ else if (framebufferObject->getStencilbufferType() != GL_NONE)
+ {
+ depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil();
+ if (!depthStencil)
+ {
+ ERR("Depth stencil pointer unexpectedly null.");
+ return false;
+ }
+
+ stencilbufferSerial = framebufferObject->getStencilbuffer()->getSerial();
+ }
+
+ if (depthbufferSerial != mAppliedDepthbufferSerial ||
+ stencilbufferSerial != mAppliedStencilbufferSerial ||
+ !mDepthStencilInitialized)
+ {
+ device->SetDepthStencilSurface(depthStencil);
+ mAppliedDepthbufferSerial = depthbufferSerial;
+ mAppliedStencilbufferSerial = stencilbufferSerial;
+ mDepthStencilInitialized = true;
+ }
+
+ D3DVIEWPORT9 viewport;
+ D3DSURFACE_DESC desc;
+ renderTarget->GetDesc(&desc);
+
+ float zNear = clamp01(mState.zNear);
+ float zFar = clamp01(mState.zFar);
+
+ if (ignoreViewport)
+ {
+ viewport.X = 0;
+ viewport.Y = 0;
+ viewport.Width = desc.Width;
+ viewport.Height = desc.Height;
+ viewport.MinZ = 0.0f;
+ viewport.MaxZ = 1.0f;
+ }
+ else
+ {
+ RECT rect = transformPixelRect(mState.viewportX, mState.viewportY, mState.viewportWidth, mState.viewportHeight, desc.Height);
+ viewport.X = clamp(rect.left, 0L, static_cast<LONG>(desc.Width));
+ viewport.Y = clamp(rect.top, 0L, static_cast<LONG>(desc.Height));
+ viewport.Width = clamp(rect.right - rect.left, 0L, static_cast<LONG>(desc.Width) - static_cast<LONG>(viewport.X));
+ viewport.Height = clamp(rect.bottom - rect.top, 0L, static_cast<LONG>(desc.Height) - static_cast<LONG>(viewport.Y));
+ viewport.MinZ = zNear;
+ viewport.MaxZ = zFar;
+ }
+
+ if (viewport.Width <= 0 || viewport.Height <= 0)
+ {
+ return false; // Nothing to render
+ }
+
+ device->SetViewport(&viewport);
+
+ if (mScissorStateDirty)
+ {
+ if (mState.scissorTest)
+ {
+ RECT rect = transformPixelRect(mState.scissorX, mState.scissorY, mState.scissorWidth, mState.scissorHeight, desc.Height);
+ rect.left = clamp(rect.left, 0L, static_cast<LONG>(desc.Width));
+ rect.top = clamp(rect.top, 0L, static_cast<LONG>(desc.Height));
+ rect.right = clamp(rect.right, 0L, static_cast<LONG>(desc.Width));
+ rect.bottom = clamp(rect.bottom, 0L, static_cast<LONG>(desc.Height));
+ device->SetScissorRect(&rect);
+ device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
+ }
+
+ mScissorStateDirty = false;
+ }
+
+ if (mState.currentProgram)
+ {
+ Program *programObject = getCurrentProgram();
+
+ GLint halfPixelSize = programObject->getDxHalfPixelSizeLocation();
+ GLfloat xy[2] = {1.0f / viewport.Width, -1.0f / viewport.Height};
+ programObject->setUniform2fv(halfPixelSize, 1, xy);
+
+ GLint viewport = programObject->getDxViewportLocation();
+ GLfloat whxy[4] = {mState.viewportWidth / 2.0f, mState.viewportHeight / 2.0f,
+ (float)mState.viewportX + mState.viewportWidth / 2.0f,
+ (float)mState.viewportY + mState.viewportHeight / 2.0f};
+ programObject->setUniform4fv(viewport, 1, whxy);
+
+ GLint depth = programObject->getDxDepthLocation();
+ GLfloat dz[2] = {(zFar - zNear) / 2.0f, (zNear + zFar) / 2.0f};
+ programObject->setUniform2fv(depth, 1, dz);
+
+ GLint depthRange = programObject->getDxDepthRangeLocation();
+ GLfloat nearFarDiff[3] = {zNear, zFar, zFar - zNear};
+ programObject->setUniform3fv(depthRange, 1, nearFarDiff);
+ }
+
+ return true;
+}
+
+// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device
+void Context::applyState(GLenum drawMode)
+{
+ IDirect3DDevice9 *device = getDevice();
+ Program *programObject = getCurrentProgram();
+
+ Framebuffer *framebufferObject = getDrawFramebuffer();
+
+ GLenum adjustedFrontFace = adjustWinding(mState.frontFace);
+
+ GLint frontCCW = programObject->getDxFrontCCWLocation();
+ GLint ccw = (adjustedFrontFace == GL_CCW);
+ programObject->setUniform1iv(frontCCW, 1, &ccw);
+
+ GLint pointsOrLines = programObject->getDxPointsOrLinesLocation();
+ GLint alwaysFront = !isTriangleMode(drawMode);
+ programObject->setUniform1iv(pointsOrLines, 1, &alwaysFront);
+
+ egl::Display *display = getDisplay();
+ D3DADAPTER_IDENTIFIER9 *identifier = display->getAdapterIdentifier();
+ bool zeroColorMaskAllowed = identifier->VendorId != 0x1002;
+ // Apparently some ATI cards have a bug where a draw with a zero color
+ // write mask can cause later draws to have incorrect results. Instead,
+ // set a nonzero color write mask but modify the blend state so that no
+ // drawing is done.
+ // http://code.google.com/p/angleproject/issues/detail?id=169
+
+ if (mCullStateDirty || mFrontFaceDirty)
+ {
+ if (mState.cullFace)
+ {
+ device->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, adjustedFrontFace));
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ }
+
+ mCullStateDirty = false;
+ }
+
+ if (mDepthStateDirty)
+ {
+ if (mState.depthTest)
+ {
+ device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
+ device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc));
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+ }
+
+ mDepthStateDirty = false;
+ }
+
+ if (!zeroColorMaskAllowed && (mMaskStateDirty || mBlendStateDirty))
+ {
+ mBlendStateDirty = true;
+ mMaskStateDirty = true;
+ }
+
+ if (mBlendStateDirty)
+ {
+ if (mState.blend)
+ {
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ if (mState.sourceBlendRGB != GL_CONSTANT_ALPHA && mState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
+ mState.destBlendRGB != GL_CONSTANT_ALPHA && mState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
+ {
+ device->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor));
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(mState.blendColor.alpha),
+ unorm<8>(mState.blendColor.alpha),
+ unorm<8>(mState.blendColor.alpha),
+ unorm<8>(mState.blendColor.alpha)));
+ }
+
+ device->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(mState.sourceBlendRGB));
+ device->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(mState.destBlendRGB));
+ device->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(mState.blendEquationRGB));
+
+ if (mState.sourceBlendRGB != mState.sourceBlendAlpha ||
+ mState.destBlendRGB != mState.destBlendAlpha ||
+ mState.blendEquationRGB != mState.blendEquationAlpha)
+ {
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+
+ device->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(mState.sourceBlendAlpha));
+ device->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(mState.destBlendAlpha));
+ device->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(mState.blendEquationAlpha));
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+ }
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ }
+
+ mBlendStateDirty = false;
+ }
+
+ if (mStencilStateDirty || mFrontFaceDirty)
+ {
+ if (mState.stencilTest && framebufferObject->hasStencil())
+ {
+ device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
+
+ // FIXME: Unsupported by D3D9
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
+ const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
+ if (mState.stencilWritemask != mState.stencilBackWritemask ||
+ mState.stencilRef != mState.stencilBackRef ||
+ mState.stencilMask != mState.stencilBackMask)
+ {
+ ERR("Separate front/back stencil writemasks, reference values, or stencil mask values are invalid under WebGL.");
+ return error(GL_INVALID_OPERATION);
+ }
+
+ // get the maximum size of the stencil ref
+ gl::DepthStencilbuffer *stencilbuffer = framebufferObject->getStencilbuffer();
+ GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1;
+
+ device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask);
+ device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ es2dx::ConvertComparison(mState.stencilFunc));
+
+ device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);
+ device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask);
+
+ device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ es2dx::ConvertStencilOp(mState.stencilFail));
+ device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ es2dx::ConvertStencilOp(mState.stencilPassDepthFail));
+ device->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ es2dx::ConvertStencilOp(mState.stencilPassDepthPass));
+
+ device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask);
+ device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ es2dx::ConvertComparison(mState.stencilBackFunc));
+
+ device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);
+ device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask);
+
+ device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ es2dx::ConvertStencilOp(mState.stencilBackFail));
+ device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ es2dx::ConvertStencilOp(mState.stencilBackPassDepthFail));
+ device->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ es2dx::ConvertStencilOp(mState.stencilBackPassDepthPass));
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ }
+
+ mStencilStateDirty = false;
+ mFrontFaceDirty = false;
+ }
+
+ if (mMaskStateDirty)
+ {
+ int colorMask = es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen,
+ mState.colorMaskBlue, mState.colorMaskAlpha);
+ if (colorMask == 0 && !zeroColorMaskAllowed)
+ {
+ // Enable green channel, but set blending so nothing will be drawn.
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+ device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+ device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
+ }
+ device->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE);
+
+ mMaskStateDirty = false;
+ }
+
+ if (mPolygonOffsetStateDirty)
+ {
+ if (mState.polygonOffsetFill)
+ {
+ gl::DepthStencilbuffer *depthbuffer = framebufferObject->getDepthbuffer();
+ if (depthbuffer)
+ {
+ device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor));
+ float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize()));
+ device->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias));
+ }
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
+ device->SetRenderState(D3DRS_DEPTHBIAS, 0);
+ }
+
+ mPolygonOffsetStateDirty = false;
+ }
+
+ if (mSampleStateDirty)
+ {
+ if (mState.sampleAlphaToCoverage)
+ {
+ FIXME("Sample alpha to coverage is unimplemented.");
+ }
+
+ device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
+ if (mState.sampleCoverage)
+ {
+ unsigned int mask = 0;
+ if (mState.sampleCoverageValue != 0)
+ {
+ float threshold = 0.5f;
+
+ for (int i = 0; i < framebufferObject->getSamples(); ++i)
+ {
+ mask <<= 1;
+
+ if ((i + 1) * mState.sampleCoverageValue >= threshold)
+ {
+ threshold += 1.0f;
+ mask |= 1;
+ }
+ }
+ }
+
+ if (mState.sampleCoverageInvert)
+ {
+ mask = ~mask;
+ }
+
+ device->SetRenderState(D3DRS_MULTISAMPLEMASK, mask);
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+ }
+
+ mSampleStateDirty = false;
+ }
+
+ if (mDitherStateDirty)
+ {
+ device->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE);
+
+ mDitherStateDirty = false;
+ }
+}
+
+GLenum Context::applyVertexBuffer(GLint first, GLsizei count)
+{
+ TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS];
+
+ GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes);
+ if (err != GL_NO_ERROR)
+ {
+ return err;
+ }
+
+ return mVertexDeclarationCache.applyDeclaration(attributes, getCurrentProgram());
+}
+
+// Applies the indices and element array bindings to the Direct3D 9 device
+GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
+{
+ IDirect3DDevice9 *device = getDevice();
+ GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo);
+
+ if (err == GL_NO_ERROR)
+ {
+ device->SetIndices(indexInfo->indexBuffer);
+ }
+
+ return err;
+}
+
+// Applies the shaders and shader constants to the Direct3D 9 device
+void Context::applyShaders()
+{
+ IDirect3DDevice9 *device = getDevice();
+ Program *programObject = getCurrentProgram();
+ IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader();
+ IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader();
+
+ device->SetVertexShader(vertexShader);
+ device->SetPixelShader(pixelShader);
+
+ if (programObject->getSerial() != mAppliedProgramSerial)
+ {
+ programObject->dirtyAllUniforms();
+ mAppliedProgramSerial = programObject->getSerial();
+ }
+
+ programObject->applyUniforms();
+}
+
+// Applies the textures and sampler states to the Direct3D 9 device
+void Context::applyTextures()
+{
+ applyTextures(SAMPLER_PIXEL);
+
+ if (mSupportsVertexTexture)
+ {
+ applyTextures(SAMPLER_VERTEX);
+ }
+}
+
+// For each Direct3D 9 sampler of either the pixel or vertex stage,
+// looks up the corresponding OpenGL texture image unit and texture type,
+// and sets the texture and its addressing/filtering state (or NULL when inactive).
+void Context::applyTextures(SamplerType type)
+{
+ IDirect3DDevice9 *device = getDevice();
+ Program *programObject = getCurrentProgram();
+
+ int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; // Range of Direct3D 9 samplers of given sampler type
+
+ for (int samplerIndex = 0; samplerIndex < samplerCount; samplerIndex++)
+ {
+ int textureUnit = programObject->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index
+ int d3dSampler = (type == SAMPLER_PIXEL) ? samplerIndex : D3DVERTEXTEXTURESAMPLER0 + samplerIndex;
+ unsigned int *appliedTextureSerial = (type == SAMPLER_PIXEL) ? mAppliedTextureSerialPS : mAppliedTextureSerialVS;
+
+ if (textureUnit != -1)
+ {
+ TextureType textureType = programObject->getSamplerTextureType(type, samplerIndex);
+
+ Texture *texture = getSamplerTexture(textureUnit, textureType);
+
+ if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyParameter() || texture->isDirtyImage())
+ {
+ IDirect3DBaseTexture9 *d3dTexture = texture->getTexture();
+
+ if (d3dTexture)
+ {
+ if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyParameter())
+ {
+ GLenum wrapS = texture->getWrapS();
+ GLenum wrapT = texture->getWrapT();
+ GLenum minFilter = texture->getMinFilter();
+ GLenum magFilter = texture->getMagFilter();
+
+ device->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
+ device->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
+
+ device->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
+ D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
+ es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter);
+ device->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
+ device->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
+ }
+
+ if (appliedTextureSerial[samplerIndex] != texture->getSerial() || texture->isDirtyImage())
+ {
+ device->SetTexture(d3dSampler, d3dTexture);
+ }
+ }
+ else
+ {
+ device->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture());
+ }
+
+ appliedTextureSerial[samplerIndex] = texture->getSerial();
+ texture->resetDirty();
+ }
+ }
+ else
+ {
+ if (appliedTextureSerial[samplerIndex] != 0)
+ {
+ device->SetTexture(d3dSampler, NULL);
+ appliedTextureSerial[samplerIndex] = 0;
+ }
+ }
+ }
+}
+
+void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+{
+ Framebuffer *framebuffer = getReadFramebuffer();
+
+ if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if (getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ return; // Context must be lost, return silently
+ }
+
+ IDirect3DDevice9 *device = getDevice();
+
+ D3DSURFACE_DESC desc;
+ renderTarget->GetDesc(&desc);
+
+ IDirect3DSurface9 *systemSurface;
+ HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ ASSERT(SUCCEEDED(result));
+
+ if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
+ {
+ UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
+ }
+
+ result = device->GetRenderTargetData(renderTarget, systemSurface);
+
+ if (FAILED(result))
+ {
+ systemSurface->Release();
+
+ switch (result)
+ {
+ case D3DERR_DRIVERINTERNALERROR:
+ case D3DERR_DEVICELOST:
+ return error(GL_OUT_OF_MEMORY);
+ default:
+ UNREACHABLE();
+ return; // No sensible error to generate
+ }
+ }
+
+ D3DLOCKED_RECT lock;
+ RECT rect = transformPixelRect(x, y, width, height, desc.Height);
+ rect.left = clamp(rect.left, 0L, static_cast<LONG>(desc.Width));
+ rect.top = clamp(rect.top, 0L, static_cast<LONG>(desc.Height));
+ rect.right = clamp(rect.right, 0L, static_cast<LONG>(desc.Width));
+ rect.bottom = clamp(rect.bottom, 0L, static_cast<LONG>(desc.Height));
+
+ result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
+
+ if (FAILED(result))
+ {
+ UNREACHABLE();
+ systemSurface->Release();
+
+ return; // No sensible error to generate
+ }
+
+ unsigned char *source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1);
+ unsigned char *dest = (unsigned char*)pixels;
+ unsigned short *dest16 = (unsigned short*)pixels;
+ int inputPitch = -lock.Pitch;
+ GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment);
+
+ for (int j = 0; j < rect.bottom - rect.top; j++)
+ {
+ if (desc.Format == D3DFMT_A8R8G8B8 &&
+ format == GL_BGRA_EXT &&
+ type == GL_UNSIGNED_BYTE)
+ {
+ // Fast path for EXT_read_format_bgra, given
+ // an RGBA source buffer. Note that buffers with no
+ // alpha go through the slow path below.
+ memcpy(dest + j * outputPitch,
+ source + j * inputPitch,
+ (rect.right - rect.left) * 4);
+ continue;
+ }
+
+ for (int i = 0; i < rect.right - rect.left; i++)
+ {
+ float r;
+ float g;
+ float b;
+ float a;
+
+ switch (desc.Format)
+ {
+ case D3DFMT_R5G6B5:
+ {
+ unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch);
+
+ a = 1.0f;
+ b = (rgb & 0x001F) * (1.0f / 0x001F);
+ g = (rgb & 0x07E0) * (1.0f / 0x07E0);
+ r = (rgb & 0xF800) * (1.0f / 0xF800);
+ }
+ break;
+ case D3DFMT_A1R5G5B5:
+ {
+ unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch);
+
+ a = (argb & 0x8000) ? 1.0f : 0.0f;
+ b = (argb & 0x001F) * (1.0f / 0x001F);
+ g = (argb & 0x03E0) * (1.0f / 0x03E0);
+ r = (argb & 0x7C00) * (1.0f / 0x7C00);
+ }
+ break;
+ case D3DFMT_A8R8G8B8:
+ {
+ unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+
+ a = (argb & 0xFF000000) * (1.0f / 0xFF000000);
+ b = (argb & 0x000000FF) * (1.0f / 0x000000FF);
+ g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00);
+ r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000);
+ }
+ break;
+ case D3DFMT_X8R8G8B8:
+ {
+ unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+
+ a = 1.0f;
+ b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);
+ g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00);
+ r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000);
+ }
+ break;
+ case D3DFMT_A2R10G10B10:
+ {
+ unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
+
+ a = (argb & 0xC0000000) * (1.0f / 0xC0000000);
+ b = (argb & 0x000003FF) * (1.0f / 0x000003FF);
+ g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00);
+ r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000);
+ }
+ break;
+ case D3DFMT_A32B32G32R32F:
+ {
+ // float formats in D3D are stored rgba, rather than the other way round
+ r = *((float*)(source + 16 * i + j * inputPitch) + 0);
+ g = *((float*)(source + 16 * i + j * inputPitch) + 1);
+ b = *((float*)(source + 16 * i + j * inputPitch) + 2);
+ a = *((float*)(source + 16 * i + j * inputPitch) + 3);
+ }
+ break;
+ case D3DFMT_A16B16G16R16F:
+ {
+ // float formats in D3D are stored rgba, rather than the other way round
+ float abgr[4];
+
+ D3DXFloat16To32Array(abgr, (D3DXFLOAT16*)(source + 8 * i + j * inputPitch), 4);
+
+ a = abgr[3];
+ b = abgr[2];
+ g = abgr[1];
+ r = abgr[0];
+ }
+ break;
+ default:
+ UNIMPLEMENTED(); // FIXME
+ UNREACHABLE();
+ }
+
+ switch (format)
+ {
+ case GL_RGBA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * r + 0.5f);
+ dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);
+ dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * b + 0.5f);
+ dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ dest[4 * i + j * outputPitch + 0] = (unsigned char)(255 * b + 0.5f);
+ dest[4 * i + j * outputPitch + 1] = (unsigned char)(255 * g + 0.5f);
+ dest[4 * i + j * outputPitch + 2] = (unsigned char)(255 * r + 0.5f);
+ dest[4 * i + j * outputPitch + 3] = (unsigned char)(255 * a + 0.5f);
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
+ // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
+ // this type is packed as follows:
+ // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ // --------------------------------------------------------------------------------
+ // | 4th | 3rd | 2nd | 1st component |
+ // --------------------------------------------------------------------------------
+ // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
+ dest16[i + j * outputPitch / sizeof(unsigned short)] =
+ ((unsigned short)(15 * a + 0.5f) << 12)|
+ ((unsigned short)(15 * r + 0.5f) << 8) |
+ ((unsigned short)(15 * g + 0.5f) << 4) |
+ ((unsigned short)(15 * b + 0.5f) << 0);
+ break;
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
+ // According to the desktop GL spec in the "Transfer of Pixel Rectangles" section
+ // this type is packed as follows:
+ // 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ // --------------------------------------------------------------------------------
+ // | 4th | 3rd | 2nd | 1st component |
+ // --------------------------------------------------------------------------------
+ // in the case of BGRA_EXT, B is the first component, G the second, and so forth.
+ dest16[i + j * outputPitch / sizeof(unsigned short)] =
+ ((unsigned short)( a + 0.5f) << 15) |
+ ((unsigned short)(31 * r + 0.5f) << 10) |
+ ((unsigned short)(31 * g + 0.5f) << 5) |
+ ((unsigned short)(31 * b + 0.5f) << 0);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_RGB: // IMPLEMENTATION_COLOR_READ_FORMAT
+ switch (type)
+ {
+ case GL_UNSIGNED_SHORT_5_6_5: // IMPLEMENTATION_COLOR_READ_TYPE
+ dest16[i + j * outputPitch / sizeof(unsigned short)] =
+ ((unsigned short)(31 * b + 0.5f) << 0) |
+ ((unsigned short)(63 * g + 0.5f) << 5) |
+ ((unsigned short)(31 * r + 0.5f) << 11);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+
+ systemSurface->UnlockRect();
+
+ systemSurface->Release();
+}
+
+void Context::clear(GLbitfield mask)
+{
+ Framebuffer *framebufferObject = getDrawFramebuffer();
+
+ if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+ DWORD flags = 0;
+
+ if (mask & GL_COLOR_BUFFER_BIT)
+ {
+ mask &= ~GL_COLOR_BUFFER_BIT;
+
+ if (framebufferObject->getColorbufferType() != GL_NONE)
+ {
+ flags |= D3DCLEAR_TARGET;
+ }
+ }
+
+ if (mask & GL_DEPTH_BUFFER_BIT)
+ {
+ mask &= ~GL_DEPTH_BUFFER_BIT;
+ if (mState.depthMask && framebufferObject->getDepthbufferType() != GL_NONE)
+ {
+ flags |= D3DCLEAR_ZBUFFER;
+ }
+ }
+
+ GLuint stencilUnmasked = 0x0;
+
+ if (mask & GL_STENCIL_BUFFER_BIT)
+ {
+ mask &= ~GL_STENCIL_BUFFER_BIT;
+ if (framebufferObject->getStencilbufferType() != GL_NONE)
+ {
+ IDirect3DSurface9 *depthStencil = framebufferObject->getStencilbuffer()->getDepthStencil();
+ if (!depthStencil)
+ {
+ ERR("Depth stencil pointer unexpectedly null.");
+ return;
+ }
+
+ D3DSURFACE_DESC desc;
+ depthStencil->GetDesc(&desc);
+
+ unsigned int stencilSize = dx2es::GetStencilSize(desc.Format);
+ stencilUnmasked = (0x1 << stencilSize) - 1;
+
+ if (stencilUnmasked != 0x0)
+ {
+ flags |= D3DCLEAR_STENCIL;
+ }
+ }
+ }
+
+ if (mask != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (!applyRenderTarget(true)) // Clips the clear to the scissor rectangle but not the viewport
+ {
+ return;
+ }
+
+ D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(mState.colorClearValue.alpha),
+ unorm<8>(mState.colorClearValue.red),
+ unorm<8>(mState.colorClearValue.green),
+ unorm<8>(mState.colorClearValue.blue));
+ float depth = clamp01(mState.depthClearValue);
+ int stencil = mState.stencilClearValue & 0x000000FF;
+
+ IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ return; // Context must be lost, return silently
+ }
+
+ D3DSURFACE_DESC desc;
+ renderTarget->GetDesc(&desc);
+
+ bool alphaUnmasked = (dx2es::GetAlphaSize(desc.Format) == 0) || mState.colorMaskAlpha;
+
+ const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) &&
+ (mState.stencilWritemask & stencilUnmasked) != stencilUnmasked;
+ const bool needMaskedColorClear = (flags & D3DCLEAR_TARGET) &&
+ !(mState.colorMaskRed && mState.colorMaskGreen &&
+ mState.colorMaskBlue && alphaUnmasked);
+
+ if (needMaskedColorClear || needMaskedStencilClear)
+ {
+ // State which is altered in all paths from this point to the clear call is saved.
+ // State which is altered in only some paths will be flagged dirty in the case that
+ // that path is taken.
+ HRESULT hr;
+ if (mMaskedClearSavedState == NULL)
+ {
+ hr = device->BeginStateBlock();
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+
+ device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+ device->SetRenderState(D3DRS_ZENABLE, FALSE);
+ device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+ device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ device->SetPixelShader(NULL);
+ device->SetVertexShader(NULL);
+ device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+ device->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+ device->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ hr = device->EndStateBlock(&mMaskedClearSavedState);
+ ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
+ }
+
+ ASSERT(mMaskedClearSavedState != NULL);
+
+ if (mMaskedClearSavedState != NULL)
+ {
+ hr = mMaskedClearSavedState->Capture();
+ ASSERT(SUCCEEDED(hr));
+ }
+
+ device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+ device->SetRenderState(D3DRS_ZENABLE, FALSE);
+ device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+
+ if (flags & D3DCLEAR_TARGET)
+ {
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha));
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+ }
+
+ if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL))
+ {
+ device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+ device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
+ device->SetRenderState(D3DRS_STENCILREF, stencil);
+ device->SetRenderState(D3DRS_STENCILWRITEMASK, mState.stencilWritemask);
+ device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
+ device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
+ device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
+ mStencilStateDirty = true;
+ }
+ else
+ {
+ device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ }
+
+ device->SetPixelShader(NULL);
+ device->SetVertexShader(NULL);
+ device->SetFVF(D3DFVF_XYZRHW);
+ device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+ device->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+ device->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges
+ quad[0][0] = -0.5f;
+ quad[0][1] = desc.Height - 0.5f;
+ quad[0][2] = 0.0f;
+ quad[0][3] = 1.0f;
+
+ quad[1][0] = desc.Width - 0.5f;
+ quad[1][1] = desc.Height - 0.5f;
+ quad[1][2] = 0.0f;
+ quad[1][3] = 1.0f;
+
+ quad[2][0] = -0.5f;
+ quad[2][1] = -0.5f;
+ quad[2][2] = 0.0f;
+ quad[2][3] = 1.0f;
+
+ quad[3][0] = desc.Width - 0.5f;
+ quad[3][1] = -0.5f;
+ quad[3][2] = 0.0f;
+ quad[3][3] = 1.0f;
+
+ display->startScene();
+ device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
+
+ if (flags & D3DCLEAR_ZBUFFER)
+ {
+ device->SetRenderState(D3DRS_ZENABLE, TRUE);
+ device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
+ device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
+ }
+
+ if (mMaskedClearSavedState != NULL)
+ {
+ mMaskedClearSavedState->Apply();
+ }
+ }
+ else if (flags)
+ {
+ device->Clear(0, NULL, flags, color, depth, stencil);
+ }
+}
+
+void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ if (!mState.currentProgram)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+ D3DPRIMITIVETYPE primitiveType;
+ int primitiveCount;
+
+ if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
+ return error(GL_INVALID_ENUM);
+
+ if (primitiveCount <= 0)
+ {
+ return;
+ }
+
+ if (!applyRenderTarget(false))
+ {
+ return;
+ }
+
+ applyState(mode);
+
+ GLenum err = applyVertexBuffer(first, count);
+ if (err != GL_NO_ERROR)
+ {
+ return error(err);
+ }
+
+ applyShaders();
+ applyTextures();
+
+ if (!getCurrentProgram()->validateSamplers(false))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!cullSkipsDraw(mode))
+ {
+ display->startScene();
+
+ device->DrawPrimitive(primitiveType, 0, primitiveCount);
+
+ if (mode == GL_LINE_LOOP) // Draw the last segment separately
+ {
+ drawClosingLine(first, first + count - 1);
+ }
+ }
+}
+
+void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
+{
+ if (!mState.currentProgram)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!indices && !mState.elementArrayBuffer)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+ D3DPRIMITIVETYPE primitiveType;
+ int primitiveCount;
+
+ if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
+ return error(GL_INVALID_ENUM);
+
+ if (primitiveCount <= 0)
+ {
+ return;
+ }
+
+ if (!applyRenderTarget(false))
+ {
+ return;
+ }
+
+ applyState(mode);
+
+ TranslatedIndexData indexInfo;
+ GLenum err = applyIndexBuffer(indices, count, mode, type, &indexInfo);
+ if (err != GL_NO_ERROR)
+ {
+ return error(err);
+ }
+
+ GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
+ err = applyVertexBuffer(indexInfo.minIndex, vertexCount);
+ if (err != GL_NO_ERROR)
+ {
+ return error(err);
+ }
+
+ applyShaders();
+ applyTextures();
+
+ if (!getCurrentProgram()->validateSamplers(false))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!cullSkipsDraw(mode))
+ {
+ display->startScene();
+
+ device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount);
+
+ if (mode == GL_LINE_LOOP) // Draw the last segment separately
+ {
+ drawClosingLine(count, type, indices);
+ }
+ }
+}
+
+void Context::finish()
+{
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+ IDirect3DQuery9 *occlusionQuery = NULL;
+ HRESULT result;
+
+ result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery);
+ if (FAILED(result))
+ {
+ ERR("CreateQuery failed hr=%x\n", result);
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+ ASSERT(false);
+ return;
+ }
+
+ IDirect3DStateBlock9 *savedState = NULL;
+ result = device->CreateStateBlock(D3DSBT_ALL, &savedState);
+ if (FAILED(result))
+ {
+ ERR("CreateStateBlock failed hr=%x\n", result);
+ occlusionQuery->Release();
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+ ASSERT(false);
+ return;
+ }
+
+ result = occlusionQuery->Issue(D3DISSUE_BEGIN);
+ if (FAILED(result))
+ {
+ ERR("occlusionQuery->Issue(BEGIN) failed hr=%x\n", result);
+ occlusionQuery->Release();
+ savedState->Release();
+ ASSERT(false);
+ return;
+ }
+
+ // Render something outside the render target
+ device->SetPixelShader(NULL);
+ device->SetVertexShader(NULL);
+ device->SetFVF(D3DFVF_XYZRHW);
+ float data[4] = {-1.0f, -1.0f, -1.0f, 1.0f};
+ display->startScene();
+ device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data));
+
+ result = occlusionQuery->Issue(D3DISSUE_END);
+ if (FAILED(result))
+ {
+ ERR("occlusionQuery->Issue(END) failed hr=%x\n", result);
+ occlusionQuery->Release();
+ savedState->Apply();
+ savedState->Release();
+ ASSERT(false);
+ return;
+ }
+
+ while ((result = occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH)) == S_FALSE)
+ {
+ // Keep polling, but allow other threads to do something useful first
+ Sleep(0);
+ }
+
+ occlusionQuery->Release();
+ savedState->Apply();
+ savedState->Release();
+
+ if (result == D3DERR_DEVICELOST)
+ {
+ error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void Context::flush()
+{
+ IDirect3DDevice9 *device = getDevice();
+ IDirect3DQuery9 *eventQuery = NULL;
+ HRESULT result;
+
+ result = device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
+ if (FAILED(result))
+ {
+ ERR("CreateQuery failed hr=%x\n", result);
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+ ASSERT(false);
+ return;
+ }
+
+ result = eventQuery->Issue(D3DISSUE_END);
+ if (FAILED(result))
+ {
+ ERR("eventQuery->Issue(END) failed hr=%x\n", result);
+ ASSERT(false);
+ eventQuery->Release();
+ return;
+ }
+
+ result = eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH);
+ eventQuery->Release();
+
+ if (result == D3DERR_DEVICELOST)
+ {
+ error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void Context::drawClosingLine(unsigned int first, unsigned int last)
+{
+ IDirect3DDevice9 *device = getDevice();
+ IDirect3DIndexBuffer9 *indexBuffer = NULL;
+ bool succeeded = false;
+ UINT offset;
+
+ if (supports32bitIndices())
+ {
+ const int spaceNeeded = 2 * sizeof(unsigned int);
+
+ if (!mClosingIB)
+ {
+ mClosingIB = new StreamingIndexBuffer(device, CLOSING_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
+ }
+
+ mClosingIB->reserveSpace(spaceNeeded, GL_UNSIGNED_INT);
+
+ unsigned int *data = static_cast<unsigned int*>(mClosingIB->map(spaceNeeded, &offset));
+ if (data)
+ {
+ data[0] = last;
+ data[1] = first;
+ mClosingIB->unmap();
+ offset /= 4;
+ succeeded = true;
+ }
+ }
+ else
+ {
+ const int spaceNeeded = 2 * sizeof(unsigned short);
+
+ if (!mClosingIB)
+ {
+ mClosingIB = new StreamingIndexBuffer(device, CLOSING_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
+ }
+
+ mClosingIB->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT);
+
+ unsigned short *data = static_cast<unsigned short*>(mClosingIB->map(spaceNeeded, &offset));
+ if (data)
+ {
+ data[0] = last;
+ data[1] = first;
+ mClosingIB->unmap();
+ offset /= 2;
+ succeeded = true;
+ }
+ }
+
+ if (succeeded)
+ {
+ device->SetIndices(mClosingIB->getBuffer());
+
+ device->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, last, offset, 1);
+ }
+ else
+ {
+ ERR("Could not create an index buffer for closing a line loop.");
+ error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void Context::drawClosingLine(GLsizei count, GLenum type, const void *indices)
+{
+ unsigned int first = 0;
+ unsigned int last = 0;
+
+ if (mState.elementArrayBuffer.get())
+ {
+ Buffer *indexBuffer = mState.elementArrayBuffer.get();
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ indices = static_cast<const GLubyte*>(indexBuffer->data()) + offset;
+ }
+
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ first = static_cast<const GLubyte*>(indices)[0];
+ last = static_cast<const GLubyte*>(indices)[count - 1];
+ break;
+ case GL_UNSIGNED_SHORT:
+ first = static_cast<const GLushort*>(indices)[0];
+ last = static_cast<const GLushort*>(indices)[count - 1];
+ break;
+ case GL_UNSIGNED_INT:
+ first = static_cast<const GLuint*>(indices)[0];
+ last = static_cast<const GLuint*>(indices)[count - 1];
+ break;
+ default: UNREACHABLE();
+ }
+
+ drawClosingLine(first, last);
+}
+
+void Context::recordInvalidEnum()
+{
+ mInvalidEnum = true;
+}
+
+void Context::recordInvalidValue()
+{
+ mInvalidValue = true;
+}
+
+void Context::recordInvalidOperation()
+{
+ mInvalidOperation = true;
+}
+
+void Context::recordOutOfMemory()
+{
+ mOutOfMemory = true;
+}
+
+void Context::recordInvalidFramebufferOperation()
+{
+ mInvalidFramebufferOperation = true;
+}
+
+// Get one of the recorded errors and clear its flag, if any.
+// [OpenGL ES 2.0.24] section 2.5 page 13.
+GLenum Context::getError()
+{
+ if (mInvalidEnum)
+ {
+ mInvalidEnum = false;
+
+ return GL_INVALID_ENUM;
+ }
+
+ if (mInvalidValue)
+ {
+ mInvalidValue = false;
+
+ return GL_INVALID_VALUE;
+ }
+
+ if (mInvalidOperation)
+ {
+ mInvalidOperation = false;
+
+ return GL_INVALID_OPERATION;
+ }
+
+ if (mOutOfMemory)
+ {
+ mOutOfMemory = false;
+
+ return GL_OUT_OF_MEMORY;
+ }
+
+ if (mInvalidFramebufferOperation)
+ {
+ mInvalidFramebufferOperation = false;
+
+ return GL_INVALID_FRAMEBUFFER_OPERATION;
+ }
+
+ return GL_NO_ERROR;
+}
+
+bool Context::supportsShaderModel3() const
+{
+ return mSupportsShaderModel3;
+}
+
+int Context::getMaximumVaryingVectors() const
+{
+ return mSupportsShaderModel3 ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2;
+}
+
+unsigned int Context::getMaximumVertexTextureImageUnits() const
+{
+ return mSupportsVertexTexture ? MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF : 0;
+}
+
+unsigned int Context::getMaximumCombinedTextureImageUnits() const
+{
+ return MAX_TEXTURE_IMAGE_UNITS + getMaximumVertexTextureImageUnits();
+}
+
+int Context::getMaximumFragmentUniformVectors() const
+{
+ return mSupportsShaderModel3 ? MAX_FRAGMENT_UNIFORM_VECTORS_SM3 : MAX_FRAGMENT_UNIFORM_VECTORS_SM2;
+}
+
+int Context::getMaxSupportedSamples() const
+{
+ return mMaxSupportedSamples;
+}
+
+int Context::getNearestSupportedSamples(D3DFORMAT format, int requested) const
+{
+ if (requested == 0)
+ {
+ return requested;
+ }
+
+ std::map<D3DFORMAT, bool *>::const_iterator itr = mMultiSampleSupport.find(format);
+ if (itr == mMultiSampleSupport.end())
+ {
+ return -1;
+ }
+
+ for (int i = requested; i <= D3DMULTISAMPLE_16_SAMPLES; ++i)
+ {
+ if (itr->second[i] && i != D3DMULTISAMPLE_NONMASKABLE)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+bool Context::supportsEventQueries() const
+{
+ return mSupportsEventQueries;
+}
+
+bool Context::supportsCompressedTextures() const
+{
+ return mSupportsCompressedTextures;
+}
+
+bool Context::supportsFloatTextures() const
+{
+ return mSupportsFloatTextures;
+}
+
+bool Context::supportsFloatLinearFilter() const
+{
+ return mSupportsFloatLinearFilter;
+}
+
+bool Context::supportsFloatRenderableTextures() const
+{
+ return mSupportsFloatRenderableTextures;
+}
+
+bool Context::supportsHalfFloatTextures() const
+{
+ return mSupportsHalfFloatTextures;
+}
+
+bool Context::supportsHalfFloatLinearFilter() const
+{
+ return mSupportsHalfFloatLinearFilter;
+}
+
+bool Context::supportsHalfFloatRenderableTextures() const
+{
+ return mSupportsHalfFloatRenderableTextures;
+}
+
+int Context::getMaximumRenderbufferDimension() const
+{
+ return mMaxRenderbufferDimension;
+}
+
+int Context::getMaximumTextureDimension() const
+{
+ return mMaxTextureDimension;
+}
+
+int Context::getMaximumCubeTextureDimension() const
+{
+ return mMaxCubeTextureDimension;
+}
+
+int Context::getMaximumTextureLevel() const
+{
+ return mMaxTextureLevel;
+}
+
+bool Context::supportsLuminanceTextures() const
+{
+ return mSupportsLuminanceTextures;
+}
+
+bool Context::supportsLuminanceAlphaTextures() const
+{
+ return mSupportsLuminanceAlphaTextures;
+}
+
+bool Context::supports32bitIndices() const
+{
+ return mSupports32bitIndices;
+}
+
+bool Context::supportsNonPower2Texture() const
+{
+ return mSupportsNonPower2Texture;
+}
+
+void Context::detachBuffer(GLuint buffer)
+{
+ // [OpenGL ES 2.0.24] section 2.9 page 22:
+ // If a buffer object is deleted while it is bound, all bindings to that object in the current context
+ // (i.e. in the thread that called Delete-Buffers) are reset to zero.
+
+ if (mState.arrayBuffer.id() == buffer)
+ {
+ mState.arrayBuffer.set(NULL);
+ }
+
+ if (mState.elementArrayBuffer.id() == buffer)
+ {
+ mState.elementArrayBuffer.set(NULL);
+ }
+
+ for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
+ {
+ if (mState.vertexAttribute[attribute].mBoundBuffer.id() == buffer)
+ {
+ mState.vertexAttribute[attribute].mBoundBuffer.set(NULL);
+ }
+ }
+}
+
+void Context::detachTexture(GLuint texture)
+{
+ // [OpenGL ES 2.0.24] section 3.8 page 84:
+ // If a texture object is deleted, it is as if all texture units which are bound to that texture object are
+ // rebound to texture object zero
+
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
+ {
+ for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++)
+ {
+ if (mState.samplerTexture[type][sampler].id() == texture)
+ {
+ mState.samplerTexture[type][sampler].set(NULL);
+ }
+ }
+ }
+
+ // [OpenGL ES 2.0.24] section 4.4 page 112:
+ // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is
+ // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this
+ // image was attached in the currently bound framebuffer.
+
+ Framebuffer *readFramebuffer = getReadFramebuffer();
+ Framebuffer *drawFramebuffer = getDrawFramebuffer();
+
+ if (readFramebuffer)
+ {
+ readFramebuffer->detachTexture(texture);
+ }
+
+ if (drawFramebuffer && drawFramebuffer != readFramebuffer)
+ {
+ drawFramebuffer->detachTexture(texture);
+ }
+}
+
+void Context::detachFramebuffer(GLuint framebuffer)
+{
+ // [OpenGL ES 2.0.24] section 4.4 page 107:
+ // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though
+ // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero.
+
+ if (mState.readFramebuffer == framebuffer)
+ {
+ bindReadFramebuffer(0);
+ }
+
+ if (mState.drawFramebuffer == framebuffer)
+ {
+ bindDrawFramebuffer(0);
+ }
+}
+
+void Context::detachRenderbuffer(GLuint renderbuffer)
+{
+ // [OpenGL ES 2.0.24] section 4.4 page 109:
+ // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer
+ // had been executed with the target RENDERBUFFER and name of zero.
+
+ if (mState.renderbuffer.id() == renderbuffer)
+ {
+ bindRenderbuffer(0);
+ }
+
+ // [OpenGL ES 2.0.24] section 4.4 page 111:
+ // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer,
+ // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment
+ // point to which this image was attached in the currently bound framebuffer.
+
+ Framebuffer *readFramebuffer = getReadFramebuffer();
+ Framebuffer *drawFramebuffer = getDrawFramebuffer();
+
+ if (readFramebuffer)
+ {
+ readFramebuffer->detachRenderbuffer(renderbuffer);
+ }
+
+ if (drawFramebuffer && drawFramebuffer != readFramebuffer)
+ {
+ drawFramebuffer->detachRenderbuffer(renderbuffer);
+ }
+}
+
+Texture *Context::getIncompleteTexture(TextureType type)
+{
+ Texture *t = mIncompleteTextures[type].get();
+
+ if (t == NULL)
+ {
+ static const GLubyte color[] = { 0, 0, 0, 255 };
+
+ switch (type)
+ {
+ default:
+ UNREACHABLE();
+ // default falls through to TEXTURE_2D
+
+ case TEXTURE_2D:
+ {
+ Texture2D *incomplete2d = new Texture2D(Texture::INCOMPLETE_TEXTURE_ID);
+ incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ t = incomplete2d;
+ }
+ break;
+
+ case TEXTURE_CUBE:
+ {
+ TextureCubeMap *incompleteCube = new TextureCubeMap(Texture::INCOMPLETE_TEXTURE_ID);
+
+ incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+
+ t = incompleteCube;
+ }
+ break;
+ }
+
+ mIncompleteTextures[type].set(t);
+ }
+
+ return t;
+}
+
+bool Context::cullSkipsDraw(GLenum drawMode)
+{
+ return mState.cullFace && mState.cullMode == GL_FRONT_AND_BACK && isTriangleMode(drawMode);
+}
+
+bool Context::isTriangleMode(GLenum drawMode)
+{
+ switch (drawMode)
+ {
+ case GL_TRIANGLES:
+ case GL_TRIANGLE_FAN:
+ case GL_TRIANGLE_STRIP:
+ return true;
+ case GL_POINTS:
+ case GL_LINES:
+ case GL_LINE_LOOP:
+ case GL_LINE_STRIP:
+ return false;
+ default: UNREACHABLE();
+ }
+
+ return false;
+}
+
+void Context::setVertexAttrib(GLuint index, const GLfloat *values)
+{
+ ASSERT(index < gl::MAX_VERTEX_ATTRIBS);
+
+ mState.vertexAttribute[index].mCurrentValue[0] = values[0];
+ mState.vertexAttribute[index].mCurrentValue[1] = values[1];
+ mState.vertexAttribute[index].mCurrentValue[2] = values[2];
+ mState.vertexAttribute[index].mCurrentValue[3] = values[3];
+
+ mVertexDataManager->dirtyCurrentValue(index);
+}
+
+void Context::initExtensionString()
+{
+ mExtensionString += "GL_OES_packed_depth_stencil ";
+ mExtensionString += "GL_EXT_texture_format_BGRA8888 ";
+ mExtensionString += "GL_EXT_read_format_bgra ";
+ mExtensionString += "GL_ANGLE_framebuffer_blit ";
+ mExtensionString += "GL_OES_rgb8_rgba8 ";
+ mExtensionString += "GL_OES_standard_derivatives ";
+
+ if (supportsEventQueries())
+ {
+ mExtensionString += "GL_NV_fence ";
+ }
+
+ if (supportsCompressedTextures())
+ {
+ mExtensionString += "GL_EXT_texture_compression_dxt1 ";
+ }
+
+ if (supportsFloatTextures())
+ {
+ mExtensionString += "GL_OES_texture_float ";
+ }
+
+ if (supportsHalfFloatTextures())
+ {
+ mExtensionString += "GL_OES_texture_half_float ";
+ }
+
+ if (supportsFloatLinearFilter())
+ {
+ mExtensionString += "GL_OES_texture_float_linear ";
+ }
+
+ if (supportsHalfFloatLinearFilter())
+ {
+ mExtensionString += "GL_OES_texture_half_float_linear ";
+ }
+
+ if (getMaxSupportedSamples() != 0)
+ {
+ mExtensionString += "GL_ANGLE_framebuffer_multisample ";
+ }
+
+ if (supports32bitIndices())
+ {
+ mExtensionString += "GL_OES_element_index_uint ";
+ }
+
+ if (supportsNonPower2Texture())
+ {
+ mExtensionString += "GL_OES_texture_npot ";
+ }
+
+ std::string::size_type end = mExtensionString.find_last_not_of(' ');
+ if (end != std::string::npos)
+ {
+ mExtensionString.resize(end+1);
+ }
+}
+
+const char *Context::getExtensionString() const
+{
+ return mExtensionString.c_str();
+}
+
+void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask)
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ Framebuffer *readFramebuffer = getReadFramebuffer();
+ Framebuffer *drawFramebuffer = getDrawFramebuffer();
+
+ if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
+ !drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if (drawFramebuffer->getSamples() != 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ int readBufferWidth = readFramebuffer->getColorbuffer()->getWidth();
+ int readBufferHeight = readFramebuffer->getColorbuffer()->getHeight();
+ int drawBufferWidth = drawFramebuffer->getColorbuffer()->getWidth();
+ int drawBufferHeight = drawFramebuffer->getColorbuffer()->getHeight();
+
+ RECT sourceRect;
+ RECT destRect;
+
+ if (srcX0 < srcX1)
+ {
+ sourceRect.left = srcX0;
+ sourceRect.right = srcX1;
+ destRect.left = dstX0;
+ destRect.right = dstX1;
+ }
+ else
+ {
+ sourceRect.left = srcX1;
+ destRect.left = dstX1;
+ sourceRect.right = srcX0;
+ destRect.right = dstX0;
+ }
+
+ if (srcY0 < srcY1)
+ {
+ sourceRect.top = readBufferHeight - srcY1;
+ destRect.top = drawBufferHeight - dstY1;
+ sourceRect.bottom = readBufferHeight - srcY0;
+ destRect.bottom = drawBufferHeight - dstY0;
+ }
+ else
+ {
+ sourceRect.top = readBufferHeight - srcY0;
+ destRect.top = drawBufferHeight - dstY0;
+ sourceRect.bottom = readBufferHeight - srcY1;
+ destRect.bottom = drawBufferHeight - dstY1;
+ }
+
+ RECT sourceScissoredRect = sourceRect;
+ RECT destScissoredRect = destRect;
+
+ if (mState.scissorTest)
+ {
+ // Only write to parts of the destination framebuffer which pass the scissor test
+ // Please note: the destRect is now in D3D-style coordinates, so the *top* of the
+ // rect will be checked against scissorY, rather than the bottom.
+ if (destRect.left < mState.scissorX)
+ {
+ int xDiff = mState.scissorX - destRect.left;
+ destScissoredRect.left = mState.scissorX;
+ sourceScissoredRect.left += xDiff;
+ }
+
+ if (destRect.right > mState.scissorX + mState.scissorWidth)
+ {
+ int xDiff = destRect.right - (mState.scissorX + mState.scissorWidth);
+ destScissoredRect.right = mState.scissorX + mState.scissorWidth;
+ sourceScissoredRect.right -= xDiff;
+ }
+
+ if (destRect.top < mState.scissorY)
+ {
+ int yDiff = mState.scissorY - destRect.top;
+ destScissoredRect.top = mState.scissorY;
+ sourceScissoredRect.top += yDiff;
+ }
+
+ if (destRect.bottom > mState.scissorY + mState.scissorHeight)
+ {
+ int yDiff = destRect.bottom - (mState.scissorY + mState.scissorHeight);
+ destScissoredRect.bottom = mState.scissorY + mState.scissorHeight;
+ sourceScissoredRect.bottom -= yDiff;
+ }
+ }
+
+ bool blitRenderTarget = false;
+ bool blitDepthStencil = false;
+
+ RECT sourceTrimmedRect = sourceScissoredRect;
+ RECT destTrimmedRect = destScissoredRect;
+
+ // The source & destination rectangles also may need to be trimmed if they fall out of the bounds of
+ // the actual draw and read surfaces.
+ if (sourceTrimmedRect.left < 0)
+ {
+ int xDiff = 0 - sourceTrimmedRect.left;
+ sourceTrimmedRect.left = 0;
+ destTrimmedRect.left += xDiff;
+ }
+
+ if (sourceTrimmedRect.right > readBufferWidth)
+ {
+ int xDiff = sourceTrimmedRect.right - readBufferWidth;
+ sourceTrimmedRect.right = readBufferWidth;
+ destTrimmedRect.right -= xDiff;
+ }
+
+ if (sourceTrimmedRect.top < 0)
+ {
+ int yDiff = 0 - sourceTrimmedRect.top;
+ sourceTrimmedRect.top = 0;
+ destTrimmedRect.top += yDiff;
+ }
+
+ if (sourceTrimmedRect.bottom > readBufferHeight)
+ {
+ int yDiff = sourceTrimmedRect.bottom - readBufferHeight;
+ sourceTrimmedRect.bottom = readBufferHeight;
+ destTrimmedRect.bottom -= yDiff;
+ }
+
+ if (destTrimmedRect.left < 0)
+ {
+ int xDiff = 0 - destTrimmedRect.left;
+ destTrimmedRect.left = 0;
+ sourceTrimmedRect.left += xDiff;
+ }
+
+ if (destTrimmedRect.right > drawBufferWidth)
+ {
+ int xDiff = destTrimmedRect.right - drawBufferWidth;
+ destTrimmedRect.right = drawBufferWidth;
+ sourceTrimmedRect.right -= xDiff;
+ }
+
+ if (destTrimmedRect.top < 0)
+ {
+ int yDiff = 0 - destTrimmedRect.top;
+ destTrimmedRect.top = 0;
+ sourceTrimmedRect.top += yDiff;
+ }
+
+ if (destTrimmedRect.bottom > drawBufferHeight)
+ {
+ int yDiff = destTrimmedRect.bottom - drawBufferHeight;
+ destTrimmedRect.bottom = drawBufferHeight;
+ sourceTrimmedRect.bottom -= yDiff;
+ }
+
+ bool partialBufferCopy = false;
+ if (sourceTrimmedRect.bottom - sourceTrimmedRect.top < readBufferHeight ||
+ sourceTrimmedRect.right - sourceTrimmedRect.left < readBufferWidth ||
+ destTrimmedRect.bottom - destTrimmedRect.top < drawBufferHeight ||
+ destTrimmedRect.right - destTrimmedRect.left < drawBufferWidth ||
+ sourceTrimmedRect.top != 0 || destTrimmedRect.top != 0 || sourceTrimmedRect.left != 0 || destTrimmedRect.left != 0)
+ {
+ partialBufferCopy = true;
+ }
+
+ if (mask & GL_COLOR_BUFFER_BIT)
+ {
+ const bool validReadType = readFramebuffer->getColorbufferType() == GL_TEXTURE_2D ||
+ readFramebuffer->getColorbufferType() == GL_RENDERBUFFER;
+ const bool validDrawType = drawFramebuffer->getColorbufferType() == GL_TEXTURE_2D ||
+ drawFramebuffer->getColorbufferType() == GL_RENDERBUFFER;
+ if (!validReadType || !validDrawType ||
+ readFramebuffer->getColorbuffer()->getD3DFormat() != drawFramebuffer->getColorbuffer()->getD3DFormat())
+ {
+ ERR("Color buffer format conversion in BlitFramebufferANGLE not supported by this implementation");
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (partialBufferCopy && readFramebuffer->getSamples() != 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ blitRenderTarget = true;
+
+ }
+
+ if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
+ {
+ DepthStencilbuffer *readDSBuffer = NULL;
+ DepthStencilbuffer *drawDSBuffer = NULL;
+
+ // We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have
+ // both a depth and stencil buffer, it will be the same buffer.
+
+ if (mask & GL_DEPTH_BUFFER_BIT)
+ {
+ if (readFramebuffer->getDepthbuffer() && drawFramebuffer->getDepthbuffer())
+ {
+ if (readFramebuffer->getDepthbufferType() != drawFramebuffer->getDepthbufferType() ||
+ readFramebuffer->getDepthbuffer()->getD3DFormat() != drawFramebuffer->getDepthbuffer()->getD3DFormat())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ blitDepthStencil = true;
+ readDSBuffer = readFramebuffer->getDepthbuffer();
+ drawDSBuffer = drawFramebuffer->getDepthbuffer();
+ }
+ }
+
+ if (mask & GL_STENCIL_BUFFER_BIT)
+ {
+ if (readFramebuffer->getStencilbuffer() && drawFramebuffer->getStencilbuffer())
+ {
+ if (readFramebuffer->getStencilbufferType() != drawFramebuffer->getStencilbufferType() ||
+ readFramebuffer->getStencilbuffer()->getD3DFormat() != drawFramebuffer->getStencilbuffer()->getD3DFormat())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ blitDepthStencil = true;
+ readDSBuffer = readFramebuffer->getStencilbuffer();
+ drawDSBuffer = drawFramebuffer->getStencilbuffer();
+ }
+ }
+
+ if (partialBufferCopy)
+ {
+ ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
+ return error(GL_INVALID_OPERATION); // only whole-buffer copies are permitted
+ }
+
+ if ((drawDSBuffer && drawDSBuffer->getSamples() != 0) ||
+ (readDSBuffer && readDSBuffer->getSamples() != 0))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+
+ if (blitRenderTarget || blitDepthStencil)
+ {
+ egl::Display *display = getDisplay();
+ display->endScene();
+
+ if (blitRenderTarget)
+ {
+ HRESULT result = device->StretchRect(readFramebuffer->getRenderTarget(), &sourceTrimmedRect,
+ drawFramebuffer->getRenderTarget(), &destTrimmedRect, D3DTEXF_NONE);
+
+ if (FAILED(result))
+ {
+ ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result);
+ return;
+ }
+ }
+
+ if (blitDepthStencil)
+ {
+ HRESULT result = device->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE);
+
+ if (FAILED(result))
+ {
+ ERR("BlitFramebufferANGLE failed: StretchRect returned %x.", result);
+ return;
+ }
+ }
+ }
+}
+
+VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
+{
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ mVertexDeclCache[i].vertexDeclaration = NULL;
+ mVertexDeclCache[i].lruCount = 0;
+ }
+}
+
+VertexDeclarationCache::~VertexDeclarationCache()
+{
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ if (mVertexDeclCache[i].vertexDeclaration)
+ {
+ mVertexDeclCache[i].vertexDeclaration->Release();
+ }
+ }
+}
+
+GLenum VertexDeclarationCache::applyDeclaration(TranslatedAttribute attributes[], Program *program)
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS + 1];
+ D3DVERTEXELEMENT9 *element = &elements[0];
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (attributes[i].active)
+ {
+ device->SetStreamSource(i, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride);
+
+ element->Stream = i;
+ element->Offset = 0;
+ element->Type = attributes[i].type;
+ element->Method = D3DDECLMETHOD_DEFAULT;
+ element->Usage = D3DDECLUSAGE_TEXCOORD;
+ element->UsageIndex = program->getSemanticIndex(i);
+ element++;
+ }
+ }
+
+ static const D3DVERTEXELEMENT9 end = D3DDECL_END();
+ *(element++) = end;
+
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
+ if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
+ {
+ entry->lruCount = ++mMaxLru;
+ device->SetVertexDeclaration(entry->vertexDeclaration);
+
+ return GL_NO_ERROR;
+ }
+ }
+
+ VertexDeclCacheEntry *lastCache = mVertexDeclCache;
+
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
+ {
+ lastCache = &mVertexDeclCache[i];
+ }
+ }
+
+ if (lastCache->vertexDeclaration != NULL)
+ {
+ lastCache->vertexDeclaration->Release();
+ lastCache->vertexDeclaration = NULL;
+ }
+
+ memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
+ device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
+ device->SetVertexDeclaration(lastCache->vertexDeclaration);
+ lastCache->lruCount = ++mMaxLru;
+
+ return GL_NO_ERROR;
+}
+
+}
+
+extern "C"
+{
+gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext)
+{
+ return new gl::Context(config, shareContext);
+}
+
+void glDestroyContext(gl::Context *context)
+{
+ delete context;
+
+ if (context == gl::getContext())
+ {
+ gl::makeCurrent(NULL, NULL, NULL);
+ }
+}
+
+void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface)
+{
+ gl::makeCurrent(context, display, surface);
+}
+
+gl::Context *glGetCurrentContext()
+{
+ return gl::getContext();
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Context.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.h
new file mode 100644
index 000000000..30026544c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.h
@@ -0,0 +1,581 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Context.h: Defines the gl::Context class, managing all GL state and performing
+// rendering operations. It is the GLES2 specific implementation of EGLContext.
+
+#ifndef LIBGLESV2_CONTEXT_H_
+#define LIBGLESV2_CONTEXT_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#define EGLAPI
+#include <EGL/egl.h>
+#include <d3d9.h>
+
+#include <map>
+#include <hash_map>
+
+#include "common/angleutils.h"
+#include "libGLESv2/ResourceManager.h"
+#include "libGLESv2/HandleAllocator.h"
+#include "libGLESv2/RefCountObject.h"
+
+namespace egl
+{
+class Display;
+class Surface;
+class Config;
+}
+
+namespace gl
+{
+struct TranslatedAttribute;
+struct TranslatedIndexData;
+
+class Buffer;
+class Shader;
+class Program;
+class Texture;
+class Texture2D;
+class TextureCubeMap;
+class Framebuffer;
+class Renderbuffer;
+class RenderbufferStorage;
+class Colorbuffer;
+class Depthbuffer;
+class StreamingIndexBuffer;
+class Stencilbuffer;
+class DepthStencilbuffer;
+class VertexDataManager;
+class IndexDataManager;
+class Blit;
+class Fence;
+
+enum
+{
+ MAX_VERTEX_ATTRIBS = 16,
+ MAX_VERTEX_UNIFORM_VECTORS = 256 - 2, // 256 is the minimum for SM2, and in practice the maximum for DX9. Reserve space for dx_HalfPixelSize and dx_DepthRange.
+ MAX_VARYING_VECTORS_SM2 = 8,
+ MAX_VARYING_VECTORS_SM3 = 10,
+ MAX_TEXTURE_IMAGE_UNITS = 16,
+ MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF = 4, // For devices supporting vertex texture fetch
+ MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF = MAX_TEXTURE_IMAGE_UNITS + MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF,
+ MAX_FRAGMENT_UNIFORM_VECTORS_SM2 = 32 - 3, // Reserve space for dx_Viewport, dx_Depth, and dx_DepthRange. dx_PointOrLines and dx_FrontCCW use separate bool registers.
+ MAX_FRAGMENT_UNIFORM_VECTORS_SM3 = 224 - 3,
+ MAX_DRAW_BUFFERS = 1,
+
+ IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB,
+ IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5
+};
+
+const float ALIASED_LINE_WIDTH_RANGE_MIN = 1.0f;
+const float ALIASED_LINE_WIDTH_RANGE_MAX = 1.0f;
+const float ALIASED_POINT_SIZE_RANGE_MIN = 1.0f;
+const float ALIASED_POINT_SIZE_RANGE_MAX_SM2 = 1.0f;
+const float ALIASED_POINT_SIZE_RANGE_MAX_SM3 = 64.0f;
+
+struct Color
+{
+ float red;
+ float green;
+ float blue;
+ float alpha;
+};
+
+// Helper structure describing a single vertex attribute
+class VertexAttribute
+{
+ public:
+ VertexAttribute() : mType(GL_FLOAT), mSize(0), mNormalized(false), mStride(0), mPointer(NULL), mArrayEnabled(false)
+ {
+ mCurrentValue[0] = 0.0f;
+ mCurrentValue[1] = 0.0f;
+ mCurrentValue[2] = 0.0f;
+ mCurrentValue[3] = 1.0f;
+ }
+
+ int typeSize() const
+ {
+ switch (mType)
+ {
+ case GL_BYTE: return mSize * sizeof(GLbyte);
+ case GL_UNSIGNED_BYTE: return mSize * sizeof(GLubyte);
+ case GL_SHORT: return mSize * sizeof(GLshort);
+ case GL_UNSIGNED_SHORT: return mSize * sizeof(GLushort);
+ case GL_FIXED: return mSize * sizeof(GLfixed);
+ case GL_FLOAT: return mSize * sizeof(GLfloat);
+ default: UNREACHABLE(); return mSize * sizeof(GLfloat);
+ }
+ }
+
+ GLsizei stride() const
+ {
+ return mStride ? mStride : typeSize();
+ }
+
+ // From glVertexAttribPointer
+ GLenum mType;
+ GLint mSize;
+ bool mNormalized;
+ GLsizei mStride; // 0 means natural stride
+
+ union
+ {
+ const void *mPointer;
+ intptr_t mOffset;
+ };
+
+ BindingPointer<Buffer> mBoundBuffer; // Captured when glVertexAttribPointer is called.
+
+ bool mArrayEnabled; // From glEnable/DisableVertexAttribArray
+ float mCurrentValue[4]; // From glVertexAttrib
+};
+
+typedef VertexAttribute VertexAttributeArray[MAX_VERTEX_ATTRIBS];
+
+// Helper structure to store all raw state
+struct State
+{
+ Color colorClearValue;
+ GLclampf depthClearValue;
+ int stencilClearValue;
+
+ bool cullFace;
+ GLenum cullMode;
+ GLenum frontFace;
+ bool depthTest;
+ GLenum depthFunc;
+ bool blend;
+ GLenum sourceBlendRGB;
+ GLenum destBlendRGB;
+ GLenum sourceBlendAlpha;
+ GLenum destBlendAlpha;
+ GLenum blendEquationRGB;
+ GLenum blendEquationAlpha;
+ Color blendColor;
+ bool stencilTest;
+ GLenum stencilFunc;
+ GLint stencilRef;
+ GLuint stencilMask;
+ GLenum stencilFail;
+ GLenum stencilPassDepthFail;
+ GLenum stencilPassDepthPass;
+ GLuint stencilWritemask;
+ GLenum stencilBackFunc;
+ GLint stencilBackRef;
+ GLuint stencilBackMask;
+ GLenum stencilBackFail;
+ GLenum stencilBackPassDepthFail;
+ GLenum stencilBackPassDepthPass;
+ GLuint stencilBackWritemask;
+ bool polygonOffsetFill;
+ GLfloat polygonOffsetFactor;
+ GLfloat polygonOffsetUnits;
+ bool sampleAlphaToCoverage;
+ bool sampleCoverage;
+ GLclampf sampleCoverageValue;
+ bool sampleCoverageInvert;
+ bool scissorTest;
+ bool dither;
+
+ GLfloat lineWidth;
+
+ GLenum generateMipmapHint;
+ GLenum fragmentShaderDerivativeHint;
+
+ GLint viewportX;
+ GLint viewportY;
+ GLsizei viewportWidth;
+ GLsizei viewportHeight;
+ float zNear;
+ float zFar;
+
+ GLint scissorX;
+ GLint scissorY;
+ GLsizei scissorWidth;
+ GLsizei scissorHeight;
+
+ bool colorMaskRed;
+ bool colorMaskGreen;
+ bool colorMaskBlue;
+ bool colorMaskAlpha;
+ bool depthMask;
+
+ unsigned int activeSampler; // Active texture unit selector - GL_TEXTURE0
+ BindingPointer<Buffer> arrayBuffer;
+ BindingPointer<Buffer> elementArrayBuffer;
+ GLuint readFramebuffer;
+ GLuint drawFramebuffer;
+ BindingPointer<Renderbuffer> renderbuffer;
+ GLuint currentProgram;
+
+ VertexAttribute vertexAttribute[MAX_VERTEX_ATTRIBS];
+ BindingPointer<Texture> samplerTexture[TEXTURE_TYPE_COUNT][MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
+
+ GLint unpackAlignment;
+ GLint packAlignment;
+};
+
+// Helper class to construct and cache vertex declarations
+class VertexDeclarationCache
+{
+ public:
+ VertexDeclarationCache();
+ ~VertexDeclarationCache();
+
+ GLenum applyDeclaration(TranslatedAttribute attributes[], Program *program);
+
+ private:
+ UINT mMaxLru;
+
+ enum { NUM_VERTEX_DECL_CACHE_ENTRIES = 16 };
+
+ struct VertexDeclCacheEntry
+ {
+ D3DVERTEXELEMENT9 cachedElements[MAX_VERTEX_ATTRIBS + 1];
+ UINT lruCount;
+ IDirect3DVertexDeclaration9 *vertexDeclaration;
+ } mVertexDeclCache[NUM_VERTEX_DECL_CACHE_ENTRIES];
+};
+
+class Context
+{
+ public:
+ Context(const egl::Config *config, const gl::Context *shareContext);
+
+ ~Context();
+
+ void makeCurrent(egl::Display *display, egl::Surface *surface);
+
+ void markAllStateDirty();
+
+ // State manipulation
+ void setClearColor(float red, float green, float blue, float alpha);
+
+ void setClearDepth(float depth);
+
+ void setClearStencil(int stencil);
+
+ void setCullFace(bool enabled);
+ bool isCullFaceEnabled() const;
+
+ void setCullMode(GLenum mode);
+
+ void setFrontFace(GLenum front);
+
+ void setDepthTest(bool enabled);
+ bool isDepthTestEnabled() const;
+
+ void setDepthFunc(GLenum depthFunc);
+
+ void setDepthRange(float zNear, float zFar);
+
+ void setBlend(bool enabled);
+ bool isBlendEnabled() const;
+
+ void setBlendFactors(GLenum sourceRGB, GLenum destRGB, GLenum sourceAlpha, GLenum destAlpha);
+ void setBlendColor(float red, float green, float blue, float alpha);
+ void setBlendEquation(GLenum rgbEquation, GLenum alphaEquation);
+
+ void setStencilTest(bool enabled);
+ bool isStencilTestEnabled() const;
+
+ void setStencilParams(GLenum stencilFunc, GLint stencilRef, GLuint stencilMask);
+ void setStencilBackParams(GLenum stencilBackFunc, GLint stencilBackRef, GLuint stencilBackMask);
+ void setStencilWritemask(GLuint stencilWritemask);
+ void setStencilBackWritemask(GLuint stencilBackWritemask);
+ void setStencilOperations(GLenum stencilFail, GLenum stencilPassDepthFail, GLenum stencilPassDepthPass);
+ void setStencilBackOperations(GLenum stencilBackFail, GLenum stencilBackPassDepthFail, GLenum stencilBackPassDepthPass);
+
+ void setPolygonOffsetFill(bool enabled);
+ bool isPolygonOffsetFillEnabled() const;
+
+ void setPolygonOffsetParams(GLfloat factor, GLfloat units);
+
+ void setSampleAlphaToCoverage(bool enabled);
+ bool isSampleAlphaToCoverageEnabled() const;
+
+ void setSampleCoverage(bool enabled);
+ bool isSampleCoverageEnabled() const;
+
+ void setSampleCoverageParams(GLclampf value, bool invert);
+
+ void setScissorTest(bool enabled);
+ bool isScissorTestEnabled() const;
+
+ void setDither(bool enabled);
+ bool isDitherEnabled() const;
+
+ void setLineWidth(GLfloat width);
+
+ void setGenerateMipmapHint(GLenum hint);
+ void setFragmentShaderDerivativeHint(GLenum hint);
+
+ void setViewportParams(GLint x, GLint y, GLsizei width, GLsizei height);
+
+ void setScissorParams(GLint x, GLint y, GLsizei width, GLsizei height);
+
+ void setColorMask(bool red, bool green, bool blue, bool alpha);
+ void setDepthMask(bool mask);
+
+ void setActiveSampler(unsigned int active);
+
+ GLuint getReadFramebufferHandle() const;
+ GLuint getDrawFramebufferHandle() const;
+ GLuint getRenderbufferHandle() const;
+
+ GLuint getArrayBufferHandle() const;
+
+ void setEnableVertexAttribArray(unsigned int attribNum, bool enabled);
+ const VertexAttribute &getVertexAttribState(unsigned int attribNum);
+ void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
+ bool normalized, GLsizei stride, const void *pointer);
+ const void *getVertexAttribPointer(unsigned int attribNum) const;
+
+ const VertexAttributeArray &getVertexAttributes();
+
+ void setUnpackAlignment(GLint alignment);
+ GLint getUnpackAlignment() const;
+
+ void setPackAlignment(GLint alignment);
+ GLint getPackAlignment() const;
+
+ // These create and destroy methods are merely pass-throughs to
+ // ResourceManager, which owns these object types
+ GLuint createBuffer();
+ GLuint createShader(GLenum type);
+ GLuint createProgram();
+ GLuint createTexture();
+ GLuint createRenderbuffer();
+
+ void deleteBuffer(GLuint buffer);
+ void deleteShader(GLuint shader);
+ void deleteProgram(GLuint program);
+ void deleteTexture(GLuint texture);
+ void deleteRenderbuffer(GLuint renderbuffer);
+
+ // Framebuffers are owned by the Context, so these methods do not pass through
+ GLuint createFramebuffer();
+ void deleteFramebuffer(GLuint framebuffer);
+
+ // Fences are owned by the Context.
+ GLuint createFence();
+ void deleteFence(GLuint fence);
+
+ void bindArrayBuffer(GLuint buffer);
+ void bindElementArrayBuffer(GLuint buffer);
+ void bindTexture2D(GLuint texture);
+ void bindTextureCubeMap(GLuint texture);
+ void bindReadFramebuffer(GLuint framebuffer);
+ void bindDrawFramebuffer(GLuint framebuffer);
+ void bindRenderbuffer(GLuint renderbuffer);
+ void useProgram(GLuint program);
+
+ void setFramebufferZero(Framebuffer *framebuffer);
+
+ void setRenderbufferStorage(RenderbufferStorage *renderbuffer);
+
+ void setVertexAttrib(GLuint index, const GLfloat *values);
+
+ Buffer *getBuffer(GLuint handle);
+ Fence *getFence(GLuint handle);
+ Shader *getShader(GLuint handle);
+ Program *getProgram(GLuint handle);
+ Texture *getTexture(GLuint handle);
+ Framebuffer *getFramebuffer(GLuint handle);
+ Renderbuffer *getRenderbuffer(GLuint handle);
+
+ Buffer *getArrayBuffer();
+ Buffer *getElementArrayBuffer();
+ Program *getCurrentProgram();
+ Texture2D *getTexture2D();
+ TextureCubeMap *getTextureCubeMap();
+ Texture *getSamplerTexture(unsigned int sampler, TextureType type);
+ Framebuffer *getReadFramebuffer();
+ Framebuffer *getDrawFramebuffer();
+
+ bool getFloatv(GLenum pname, GLfloat *params);
+ bool getIntegerv(GLenum pname, GLint *params);
+ bool getBooleanv(GLenum pname, GLboolean *params);
+
+ bool getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *numParams);
+
+ void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels);
+ void clear(GLbitfield mask);
+ void drawArrays(GLenum mode, GLint first, GLsizei count);
+ void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices);
+ void finish();
+ void flush();
+
+ // Draw the last segment of a line loop
+ void drawClosingLine(unsigned int first, unsigned int last);
+ void drawClosingLine(GLsizei count, GLenum type, const void *indices);
+
+ void recordInvalidEnum();
+ void recordInvalidValue();
+ void recordInvalidOperation();
+ void recordOutOfMemory();
+ void recordInvalidFramebufferOperation();
+
+ GLenum getError();
+
+ bool supportsShaderModel3() const;
+ int getMaximumVaryingVectors() const;
+ unsigned int getMaximumVertexTextureImageUnits() const;
+ unsigned int getMaximumCombinedTextureImageUnits() const;
+ int getMaximumFragmentUniformVectors() const;
+ int getMaximumRenderbufferDimension() const;
+ int getMaximumTextureDimension() const;
+ int getMaximumCubeTextureDimension() const;
+ int getMaximumTextureLevel() const;
+ GLsizei getMaxSupportedSamples() const;
+ int getNearestSupportedSamples(D3DFORMAT format, int requested) const;
+ const char *getExtensionString() const;
+ bool supportsEventQueries() const;
+ bool supportsCompressedTextures() const;
+ bool supportsFloatTextures() const;
+ bool supportsFloatLinearFilter() const;
+ bool supportsFloatRenderableTextures() const;
+ bool supportsHalfFloatTextures() const;
+ bool supportsHalfFloatLinearFilter() const;
+ bool supportsHalfFloatRenderableTextures() const;
+ bool supportsLuminanceTextures() const;
+ bool supportsLuminanceAlphaTextures() const;
+ bool supports32bitIndices() const;
+ bool supportsNonPower2Texture() const;
+
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask);
+
+ Blit *getBlitter() { return mBlit; }
+
+ const D3DCAPS9 &getDeviceCaps() { return mDeviceCaps; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Context);
+
+ bool applyRenderTarget(bool ignoreViewport);
+ void applyState(GLenum drawMode);
+ GLenum applyVertexBuffer(GLint first, GLsizei count);
+ GLenum applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
+ void applyShaders();
+ void applyTextures();
+ void applyTextures(SamplerType type);
+
+ void detachBuffer(GLuint buffer);
+ void detachTexture(GLuint texture);
+ void detachFramebuffer(GLuint framebuffer);
+ void detachRenderbuffer(GLuint renderbuffer);
+
+ Texture *getIncompleteTexture(TextureType type);
+
+ bool cullSkipsDraw(GLenum drawMode);
+ bool isTriangleMode(GLenum drawMode);
+
+ const egl::Config *const mConfig;
+
+ State mState;
+
+ BindingPointer<Texture2D> mTexture2DZero;
+ BindingPointer<TextureCubeMap> mTextureCubeMapZero;
+
+ typedef stdext::hash_map<GLuint, Framebuffer*> FramebufferMap;
+ FramebufferMap mFramebufferMap;
+ HandleAllocator mFramebufferHandleAllocator;
+
+ typedef stdext::hash_map<GLuint, Fence*> FenceMap;
+ FenceMap mFenceMap;
+ HandleAllocator mFenceHandleAllocator;
+
+ void initExtensionString();
+ std::string mExtensionString;
+
+ VertexDataManager *mVertexDataManager;
+ IndexDataManager *mIndexDataManager;
+
+ Blit *mBlit;
+
+ StreamingIndexBuffer *mClosingIB;
+
+ BindingPointer<Texture> mIncompleteTextures[TEXTURE_TYPE_COUNT];
+
+ // Recorded errors
+ bool mInvalidEnum;
+ bool mInvalidValue;
+ bool mInvalidOperation;
+ bool mOutOfMemory;
+ bool mInvalidFramebufferOperation;
+
+ bool mHasBeenCurrent;
+
+ unsigned int mAppliedTextureSerialPS[MAX_TEXTURE_IMAGE_UNITS];
+ unsigned int mAppliedTextureSerialVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF];
+ unsigned int mAppliedProgramSerial;
+ unsigned int mAppliedRenderTargetSerial;
+ unsigned int mAppliedDepthbufferSerial;
+ unsigned int mAppliedStencilbufferSerial;
+ bool mDepthStencilInitialized;
+
+ bool mSupportsShaderModel3;
+ bool mSupportsVertexTexture;
+ bool mSupportsNonPower2Texture;
+ int mMaxRenderbufferDimension;
+ int mMaxTextureDimension;
+ int mMaxCubeTextureDimension;
+ int mMaxTextureLevel;
+ std::map<D3DFORMAT, bool *> mMultiSampleSupport;
+ GLsizei mMaxSupportedSamples;
+ bool mSupportsEventQueries;
+ bool mSupportsCompressedTextures;
+ bool mSupportsFloatTextures;
+ bool mSupportsFloatLinearFilter;
+ bool mSupportsFloatRenderableTextures;
+ bool mSupportsHalfFloatTextures;
+ bool mSupportsHalfFloatLinearFilter;
+ bool mSupportsHalfFloatRenderableTextures;
+ bool mSupportsLuminanceTextures;
+ bool mSupportsLuminanceAlphaTextures;
+ bool mSupports32bitIndices;
+
+ // state caching flags
+ bool mClearStateDirty;
+ bool mCullStateDirty;
+ bool mDepthStateDirty;
+ bool mMaskStateDirty;
+ bool mPixelPackingStateDirty;
+ bool mBlendStateDirty;
+ bool mStencilStateDirty;
+ bool mPolygonOffsetStateDirty;
+ bool mScissorStateDirty;
+ bool mSampleStateDirty;
+ bool mFrontFaceDirty;
+ bool mDitherStateDirty;
+
+ IDirect3DStateBlock9 *mMaskedClearSavedState;
+
+ D3DCAPS9 mDeviceCaps;
+
+ ResourceManager *mResourceManager;
+
+ VertexDeclarationCache mVertexDeclarationCache;
+};
+}
+
+extern "C"
+{
+// Exported functions for use by EGL
+gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext);
+void glDestroyContext(gl::Context *context);
+void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface);
+gl::Context *glGetCurrentContext();
+__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname);
+void __stdcall glBindTexImage(egl::Surface *surface);
+}
+
+#endif // INCLUDE_CONTEXT_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.cpp
new file mode 100644
index 000000000..7fbcb6ad3
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.cpp
@@ -0,0 +1,134 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Fence.cpp: Implements the gl::Fence class, which supports the GL_NV_fence extension.
+
+#include "libGLESv2/Fence.h"
+
+#include "libGLESv2/main.h"
+
+namespace gl
+{
+
+Fence::Fence()
+{
+ mQuery = NULL;
+ mCondition = GL_NONE;
+ mStatus = GL_FALSE;
+}
+
+Fence::~Fence()
+{
+ if (mQuery != NULL)
+ {
+ mQuery->Release();
+ mQuery = NULL;
+ }
+}
+
+GLboolean Fence::isFence()
+{
+ // GL_NV_fence spec:
+ // A name returned by GenFencesNV, but not yet set via SetFenceNV, is not the name of an existing fence.
+ return mQuery != NULL;
+}
+
+void Fence::setFence(GLenum condition)
+{
+ if (mQuery != NULL)
+ {
+ mQuery->Release();
+ mQuery = NULL;
+ }
+
+ if (FAILED(getDevice()->CreateQuery(D3DQUERYTYPE_EVENT, &mQuery)))
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ HRESULT result = mQuery->Issue(D3DISSUE_END);
+ ASSERT(SUCCEEDED(result));
+
+ mCondition = condition;
+ mStatus = GL_FALSE;
+}
+
+GLboolean Fence::testFence()
+{
+ if (mQuery == NULL)
+ {
+ return error(GL_INVALID_OPERATION, GL_TRUE);
+ }
+
+ HRESULT result = mQuery->GetData(NULL, 0, D3DGETDATA_FLUSH);
+
+ if (result == D3DERR_DEVICELOST)
+ {
+ return error(GL_OUT_OF_MEMORY, GL_TRUE);
+ }
+
+ ASSERT(result == S_OK || result == S_FALSE);
+ mStatus = result == S_OK;
+ return mStatus;
+}
+
+void Fence::finishFence()
+{
+ if (mQuery == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ while (!testFence())
+ {
+ Sleep(0);
+ }
+}
+
+void Fence::getFenceiv(GLenum pname, GLint *params)
+{
+ if (mQuery == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (pname)
+ {
+ case GL_FENCE_STATUS_NV:
+ {
+ // GL_NV_fence spec:
+ // Once the status of a fence has been finished (via FinishFenceNV) or tested and the returned status is TRUE (via either TestFenceNV
+ // or GetFenceivNV querying the FENCE_STATUS_NV), the status remains TRUE until the next SetFenceNV of the fence.
+ if (mStatus)
+ {
+ params[0] = GL_TRUE;
+ return;
+ }
+
+ HRESULT result = mQuery->GetData(NULL, 0, 0);
+
+ if (result == D3DERR_DEVICELOST)
+ {
+ params[0] = GL_TRUE;
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ ASSERT(result == S_OK || result == S_FALSE);
+ mStatus = result == S_OK;
+ params[0] = mStatus;
+
+ break;
+ }
+ case GL_FENCE_CONDITION_NV:
+ params[0] = mCondition;
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ break;
+ }
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.h
new file mode 100644
index 000000000..17bad78ea
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Fence.h
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Fence.h: Defines the gl::Fence class, which supports the GL_NV_fence extension.
+
+#ifndef LIBGLESV2_FENCE_H_
+#define LIBGLESV2_FENCE_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <d3d9.h>
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+
+class Fence
+{
+ public:
+ Fence();
+ virtual ~Fence();
+
+ GLboolean isFence();
+ void setFence(GLenum condition);
+ GLboolean testFence();
+ void finishFence();
+ void getFenceiv(GLenum pname, GLint *params);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Fence);
+
+ IDirect3DQuery9* mQuery;
+ GLenum mCondition;
+ GLboolean mStatus;
+};
+
+}
+
+#endif // LIBGLESV2_FENCE_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.cpp
new file mode 100644
index 000000000..0f7ec20f8
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.cpp
@@ -0,0 +1,454 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
+
+#include "libGLESv2/Framebuffer.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/utilities.h"
+
+namespace gl
+{
+
+Framebuffer::Framebuffer()
+{
+ mColorbufferType = GL_NONE;
+ mDepthbufferType = GL_NONE;
+ mStencilbufferType = GL_NONE;
+}
+
+Framebuffer::~Framebuffer()
+{
+ mColorbufferPointer.set(NULL);
+ mDepthbufferPointer.set(NULL);
+ mStencilbufferPointer.set(NULL);
+}
+
+Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
+{
+ gl::Context *context = gl::getContext();
+ Renderbuffer *buffer = NULL;
+
+ if (type == GL_NONE)
+ {
+ buffer = NULL;
+ }
+ else if (type == GL_RENDERBUFFER)
+ {
+ buffer = context->getRenderbuffer(handle);
+ }
+ else if (IsTextureTarget(type))
+ {
+ buffer = context->getTexture(handle)->getRenderbuffer(type);
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+
+ return buffer;
+}
+
+void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
+{
+ mColorbufferType = type;
+ mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
+}
+
+void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
+{
+ mDepthbufferType = type;
+ mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
+}
+
+void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
+{
+ mStencilbufferType = type;
+ mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
+}
+
+void Framebuffer::detachTexture(GLuint texture)
+{
+ if (mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType))
+ {
+ mColorbufferType = GL_NONE;
+ mColorbufferPointer.set(NULL);
+ }
+
+ if (mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
+ {
+ mDepthbufferType = GL_NONE;
+ mDepthbufferPointer.set(NULL);
+ }
+
+ if (mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType))
+ {
+ mStencilbufferType = GL_NONE;
+ mStencilbufferPointer.set(NULL);
+ }
+}
+
+void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
+{
+ if (mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
+ {
+ mColorbufferType = GL_NONE;
+ mColorbufferPointer.set(NULL);
+ }
+
+ if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
+ {
+ mDepthbufferType = GL_NONE;
+ mDepthbufferPointer.set(NULL);
+ }
+
+ if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
+ {
+ mStencilbufferType = GL_NONE;
+ mStencilbufferPointer.set(NULL);
+ }
+}
+
+unsigned int Framebuffer::getRenderTargetSerial()
+{
+ Renderbuffer *colorbuffer = mColorbufferPointer.get();
+
+ if (colorbuffer)
+ {
+ return colorbuffer->getSerial();
+ }
+
+ return 0;
+}
+
+IDirect3DSurface9 *Framebuffer::getRenderTarget()
+{
+ Renderbuffer *colorbuffer = mColorbufferPointer.get();
+
+ if (colorbuffer)
+ {
+ return colorbuffer->getRenderTarget();
+ }
+
+ return NULL;
+}
+
+IDirect3DSurface9 *Framebuffer::getDepthStencil()
+{
+ Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
+
+ if (!depthstencilbuffer)
+ {
+ depthstencilbuffer = mStencilbufferPointer.get();
+ }
+
+ if (depthstencilbuffer)
+ {
+ return depthstencilbuffer->getDepthStencil();
+ }
+
+ return NULL;
+}
+
+unsigned int Framebuffer::getDepthbufferSerial()
+{
+ Renderbuffer *depthbuffer = mDepthbufferPointer.get();
+
+ if (depthbuffer)
+ {
+ return depthbuffer->getSerial();
+ }
+
+ return 0;
+}
+
+unsigned int Framebuffer::getStencilbufferSerial()
+{
+ Renderbuffer *stencilbuffer = mStencilbufferPointer.get();
+
+ if (stencilbuffer)
+ {
+ return stencilbuffer->getSerial();
+ }
+
+ return 0;
+}
+
+Colorbuffer *Framebuffer::getColorbuffer()
+{
+ Renderbuffer *rb = mColorbufferPointer.get();
+
+ if (rb != NULL && rb->isColorbuffer())
+ {
+ return static_cast<Colorbuffer*>(rb->getStorage());
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+DepthStencilbuffer *Framebuffer::getDepthbuffer()
+{
+ Renderbuffer *rb = mDepthbufferPointer.get();
+
+ if (rb != NULL && rb->isDepthbuffer())
+ {
+ return static_cast<DepthStencilbuffer*>(rb->getStorage());
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+DepthStencilbuffer *Framebuffer::getStencilbuffer()
+{
+ Renderbuffer *rb = mStencilbufferPointer.get();
+
+ if (rb != NULL && rb->isStencilbuffer())
+ {
+ return static_cast<DepthStencilbuffer*>(rb->getStorage());
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+GLenum Framebuffer::getColorbufferType()
+{
+ return mColorbufferType;
+}
+
+GLenum Framebuffer::getDepthbufferType()
+{
+ return mDepthbufferType;
+}
+
+GLenum Framebuffer::getStencilbufferType()
+{
+ return mStencilbufferType;
+}
+
+GLuint Framebuffer::getColorbufferHandle()
+{
+ return mColorbufferPointer.id();
+}
+
+GLuint Framebuffer::getDepthbufferHandle()
+{
+ return mDepthbufferPointer.id();
+}
+
+GLuint Framebuffer::getStencilbufferHandle()
+{
+ return mStencilbufferPointer.id();
+}
+
+bool Framebuffer::hasStencil()
+{
+ if (mStencilbufferType != GL_NONE)
+ {
+ DepthStencilbuffer *stencilbufferObject = getStencilbuffer();
+
+ if (stencilbufferObject)
+ {
+ return stencilbufferObject->getStencilSize() > 0;
+ }
+ }
+
+ return false;
+}
+
+GLenum Framebuffer::completeness()
+{
+ int width = 0;
+ int height = 0;
+ int samples = -1;
+
+ if (mColorbufferType != GL_NONE)
+ {
+ Colorbuffer *colorbuffer = getColorbuffer();
+
+ if (!colorbuffer)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (mColorbufferType == GL_RENDERBUFFER)
+ {
+ if (!gl::IsColorRenderable(colorbuffer->getInternalFormat()))
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ }
+ else if (IsTextureTarget(mColorbufferType))
+ {
+ if (IsCompressed(colorbuffer->getInternalFormat()))
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ if ((colorbuffer->getType() == GL_FLOAT && !getContext()->supportsFloatRenderableTextures()) ||
+ (colorbuffer->getType() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatRenderableTextures()))
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ if (colorbuffer->getInternalFormat() == GL_LUMINANCE || colorbuffer->getInternalFormat() == GL_LUMINANCE_ALPHA)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+ }
+ else UNREACHABLE();
+
+ width = colorbuffer->getWidth();
+ height = colorbuffer->getHeight();
+ samples = colorbuffer->getSamples();
+ }
+ else
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ }
+
+ DepthStencilbuffer *depthbuffer = NULL;
+ DepthStencilbuffer *stencilbuffer = NULL;
+
+ if (mDepthbufferType != GL_NONE)
+ {
+ if (mDepthbufferType != GL_RENDERBUFFER)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED; // Requires GL_OES_depth_texture
+ }
+
+ depthbuffer = getDepthbuffer();
+
+ if (!depthbuffer)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (width == 0)
+ {
+ width = depthbuffer->getWidth();
+ height = depthbuffer->getHeight();
+ }
+ else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+
+ if (samples == -1)
+ {
+ samples = depthbuffer->getSamples();
+ }
+ else if (samples != depthbuffer->getSamples())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+ }
+ }
+
+ if (mStencilbufferType != GL_NONE)
+ {
+ if (mStencilbufferType != GL_RENDERBUFFER)
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ stencilbuffer = getStencilbuffer();
+
+ if (!stencilbuffer)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+
+ if (width == 0)
+ {
+ width = stencilbuffer->getWidth();
+ height = stencilbuffer->getHeight();
+ }
+ else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ }
+
+ if (samples == -1)
+ {
+ samples = stencilbuffer->getSamples();
+ }
+ else if (samples != stencilbuffer->getSamples())
+ {
+ return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
+ }
+ }
+
+ if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER)
+ {
+ if (depthbuffer->getInternalFormat() != GL_DEPTH24_STENCIL8_OES ||
+ stencilbuffer->getInternalFormat() != GL_DEPTH24_STENCIL8_OES ||
+ depthbuffer->getSerial() != stencilbuffer->getSerial())
+ {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+ }
+
+ return GL_FRAMEBUFFER_COMPLETE;
+}
+
+DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil)
+{
+ mColorbufferType = GL_RENDERBUFFER;
+ mDepthbufferType = (depthStencil->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
+ mStencilbufferType = (depthStencil->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
+
+ mColorbufferPointer.set(new Renderbuffer(0, color));
+
+ Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
+ mDepthbufferPointer.set(depthStencilRenderbuffer);
+ mStencilbufferPointer.set(depthStencilRenderbuffer);
+}
+
+int Framebuffer::getSamples()
+{
+ if (completeness() == GL_FRAMEBUFFER_COMPLETE)
+ {
+ return getColorbuffer()->getSamples();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+GLenum DefaultFramebuffer::completeness()
+{
+ // The default framebuffer should always be complete
+ ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
+
+ return GL_FRAMEBUFFER_COMPLETE;
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.h
new file mode 100644
index 000000000..cf51658dd
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Framebuffer.h
@@ -0,0 +1,95 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Framebuffer.h: Defines the gl::Framebuffer class. Implements GL framebuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
+
+#ifndef LIBGLESV2_FRAMEBUFFER_H_
+#define LIBGLESV2_FRAMEBUFFER_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <d3d9.h>
+
+#include "common/angleutils.h"
+#include "libGLESv2/RefCountObject.h"
+
+namespace gl
+{
+class Renderbuffer;
+class Colorbuffer;
+class Depthbuffer;
+class Stencilbuffer;
+class DepthStencilbuffer;
+
+class Framebuffer
+{
+ public:
+ Framebuffer();
+
+ virtual ~Framebuffer();
+
+ void setColorbuffer(GLenum type, GLuint colorbuffer);
+ void setDepthbuffer(GLenum type, GLuint depthbuffer);
+ void setStencilbuffer(GLenum type, GLuint stencilbuffer);
+
+ void detachTexture(GLuint texture);
+ void detachRenderbuffer(GLuint renderbuffer);
+
+ IDirect3DSurface9 *getRenderTarget();
+ IDirect3DSurface9 *getDepthStencil();
+
+ unsigned int getRenderTargetSerial();
+ unsigned int getDepthbufferSerial();
+ unsigned int getStencilbufferSerial();
+
+ Colorbuffer *getColorbuffer();
+ DepthStencilbuffer *getDepthbuffer();
+ DepthStencilbuffer *getStencilbuffer();
+
+ GLenum getColorbufferType();
+ GLenum getDepthbufferType();
+ GLenum getStencilbufferType();
+
+ GLuint getColorbufferHandle();
+ GLuint getDepthbufferHandle();
+ GLuint getStencilbufferHandle();
+
+ bool hasStencil();
+ int getSamples();
+
+ virtual GLenum completeness();
+
+ protected:
+ GLenum mColorbufferType;
+ BindingPointer<Renderbuffer> mColorbufferPointer;
+
+ GLenum mDepthbufferType;
+ BindingPointer<Renderbuffer> mDepthbufferPointer;
+
+ GLenum mStencilbufferType;
+ BindingPointer<Renderbuffer> mStencilbufferPointer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Framebuffer);
+
+ Renderbuffer *lookupRenderbuffer(GLenum type, GLuint handle) const;
+};
+
+class DefaultFramebuffer : public Framebuffer
+{
+ public:
+ DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil);
+
+ virtual GLenum completeness();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DefaultFramebuffer);
+};
+
+}
+
+#endif // LIBGLESV2_FRAMEBUFFER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.cpp
new file mode 100644
index 000000000..c498f8a17
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.cpp
@@ -0,0 +1,63 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// HandleAllocator.cpp: Implements the gl::HandleAllocator class, which is used
+// to allocate GL handles.
+
+#include "libGLESv2/HandleAllocator.h"
+
+#include "libGLESv2/main.h"
+
+namespace gl
+{
+
+HandleAllocator::HandleAllocator() : mBaseValue(1), mNextValue(1)
+{
+}
+
+HandleAllocator::~HandleAllocator()
+{
+}
+
+void HandleAllocator::setBaseHandle(GLuint value)
+{
+ ASSERT(mBaseValue == mNextValue);
+ mBaseValue = value;
+ mNextValue = value;
+}
+
+GLuint HandleAllocator::allocate()
+{
+ if (mFreeValues.size())
+ {
+ GLuint handle = mFreeValues.back();
+ mFreeValues.pop_back();
+ return handle;
+ }
+ return mNextValue++;
+}
+
+void HandleAllocator::release(GLuint handle)
+{
+ if (handle == mNextValue - 1)
+ {
+ // Don't drop below base value
+ if(mNextValue > mBaseValue)
+ {
+ mNextValue--;
+ }
+ }
+ else
+ {
+ // Only free handles that we own - don't drop below the base value
+ if (handle >= mBaseValue)
+ {
+ mFreeValues.push_back(handle);
+ }
+ }
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.h b/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.h
new file mode 100644
index 000000000..a92e1684d
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/HandleAllocator.h
@@ -0,0 +1,45 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// HandleAllocator.h: Defines the gl::HandleAllocator class, which is used to
+// allocate GL handles.
+
+#ifndef LIBGLESV2_HANDLEALLOCATOR_H_
+#define LIBGLESV2_HANDLEALLOCATOR_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <vector>
+
+#include "common/angleutils.h"
+
+namespace gl
+{
+
+class HandleAllocator
+{
+ public:
+ HandleAllocator();
+ virtual ~HandleAllocator();
+
+ void setBaseHandle(GLuint value);
+
+ GLuint allocate();
+ void release(GLuint handle);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HandleAllocator);
+
+ GLuint mBaseValue;
+ GLuint mNextValue;
+ typedef std::vector<GLuint> HandleList;
+ HandleList mFreeValues;
+};
+
+}
+
+#endif // LIBGLESV2_HANDLEALLOCATOR_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.cpp
new file mode 100644
index 000000000..5b939b8a9
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.cpp
@@ -0,0 +1,404 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexDataManager.cpp: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#include "libGLESv2/IndexDataManager.h"
+
+#include "common/debug.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/main.h"
+
+namespace
+{
+ enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
+}
+
+namespace gl
+{
+
+IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device)
+{
+ mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
+
+ if (context->supports32bitIndices())
+ {
+ mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
+
+ if (!mStreamingBufferInt)
+ {
+ // Don't leave it in a half-initialized state
+ delete mStreamingBufferShort;
+ mStreamingBufferShort = NULL;
+ }
+ }
+ else
+ {
+ mStreamingBufferInt = NULL;
+ }
+
+ if (!mStreamingBufferShort)
+ {
+ ERR("Failed to allocate the streaming index buffer(s).");
+ }
+}
+
+IndexDataManager::~IndexDataManager()
+{
+ delete mStreamingBufferShort;
+ delete mStreamingBufferInt;
+}
+
+void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
+{
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ const GLubyte *in = static_cast<const GLubyte*>(input);
+ GLushort *out = static_cast<GLushort*>(output);
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ out[i] = in[i];
+ }
+ }
+ else if (type == GL_UNSIGNED_INT)
+ {
+ memcpy(output, input, count * sizeof(GLuint));
+ }
+ else if (type == GL_UNSIGNED_SHORT)
+ {
+ memcpy(output, input, count * sizeof(GLushort));
+ }
+ else UNREACHABLE();
+}
+
+template <class IndexType>
+void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+{
+ *minIndex = indices[0];
+ *maxIndex = indices[0];
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ if (*minIndex > indices[i]) *minIndex = indices[i];
+ if (*maxIndex < indices[i]) *maxIndex = indices[i];
+ }
+}
+
+void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+{
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
+ }
+ else if (type == GL_UNSIGNED_INT)
+ {
+ computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
+ }
+ else if (type == GL_UNSIGNED_SHORT)
+ {
+ computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
+ }
+ else UNREACHABLE();
+}
+
+GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)
+{
+ if (!mStreamingBufferShort)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ bool alignedOffset = false;
+
+ if (buffer != NULL)
+ {
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
+ case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
+ case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
+ default: UNREACHABLE(); alignedOffset = false;
+ }
+
+ if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
+ {
+ return GL_INVALID_OPERATION;
+ }
+
+ indices = static_cast<const GLubyte*>(buffer->data()) + offset;
+ }
+
+ StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
+
+ StaticIndexBuffer *staticBuffer = buffer ? buffer->getStaticIndexBuffer() : NULL;
+ IndexBuffer *indexBuffer = streamingBuffer;
+ UINT streamOffset = 0;
+
+ if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
+ {
+ indexBuffer = staticBuffer;
+ streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
+
+ if (streamOffset == -1)
+ {
+ streamOffset = (offset / typeSize(type)) * indexSize(format);
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+ staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
+ }
+ }
+ else
+ {
+ int convertCount = count;
+
+ if (staticBuffer)
+ {
+ if (staticBuffer->size() == 0 && alignedOffset)
+ {
+ indexBuffer = staticBuffer;
+ convertCount = buffer->size() / typeSize(type);
+ }
+ else
+ {
+ buffer->invalidateStaticData();
+ staticBuffer = NULL;
+ }
+ }
+
+ void *output = NULL;
+
+ if (indexBuffer)
+ {
+ indexBuffer->reserveSpace(convertCount * indexSize(format), type);
+ output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset);
+ }
+
+ if (output == NULL)
+ {
+ ERR("Failed to map index buffer.");
+ return GL_OUT_OF_MEMORY;
+ }
+
+ convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
+ indexBuffer->unmap();
+
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+
+ if (staticBuffer)
+ {
+ streamOffset = (offset / typeSize(type)) * indexSize(format);
+ staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
+ }
+ }
+
+ translated->indexBuffer = indexBuffer->getBuffer();
+ translated->startIndex = streamOffset / indexSize(format);
+
+ if (buffer)
+ {
+ buffer->promoteStaticUsage(count * typeSize(type));
+ }
+
+ return GL_NO_ERROR;
+}
+
+std::size_t IndexDataManager::indexSize(D3DFORMAT format) const
+{
+ return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short);
+}
+
+std::size_t IndexDataManager::typeSize(GLenum type) const
+{
+ switch (type)
+ {
+ case GL_UNSIGNED_INT: return sizeof(GLuint);
+ case GL_UNSIGNED_SHORT: return sizeof(GLushort);
+ case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
+ default: UNREACHABLE(); return sizeof(GLushort);
+ }
+}
+
+IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL)
+{
+ if (size > 0)
+ {
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
+ HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, pool, &mIndexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating an index buffer of size %lu.", size);
+ }
+ }
+}
+
+IndexBuffer::~IndexBuffer()
+{
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Release();
+ }
+}
+
+IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const
+{
+ return mIndexBuffer;
+}
+
+void IndexBuffer::unmap()
+{
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Unlock();
+ }
+}
+
+StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format)
+{
+ mWritePosition = 0;
+}
+
+StreamingIndexBuffer::~StreamingIndexBuffer()
+{
+}
+
+void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mIndexBuffer)
+ {
+ HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
+
+ if (FAILED(result))
+ {
+ ERR(" Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
+{
+ if (requiredSpace > mBufferSize)
+ {
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Release();
+ mIndexBuffer = NULL;
+ }
+
+ mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
+
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
+ HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+ else if (mWritePosition + requiredSpace > mBufferSize) // Recycle
+ {
+ void *dummy;
+ mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ mIndexBuffer->Unlock();
+
+ mWritePosition = 0;
+ }
+}
+
+StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN)
+{
+ mCacheType = GL_NONE;
+}
+
+StaticIndexBuffer::~StaticIndexBuffer()
+{
+}
+
+void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mIndexBuffer)
+ {
+ HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
+
+ if (FAILED(result))
+ {
+ ERR(" Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = 0;
+ }
+
+ return mapPtr;
+}
+
+void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
+{
+ if (!mIndexBuffer && mBufferSize == 0)
+ {
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY);
+ HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mBufferSize = requiredSpace;
+ mCacheType = type;
+ }
+ else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
+ {
+ // Already allocated
+ }
+ else UNREACHABLE(); // Static index buffers can't be resized
+}
+
+bool StaticIndexBuffer::lookupType(GLenum type)
+{
+ return mCacheType == type;
+}
+
+UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex)
+{
+ for (unsigned int range = 0; range < mCache.size(); range++)
+ {
+ if (mCache[range].offset == offset && mCache[range].count == count)
+ {
+ *minIndex = mCache[range].minIndex;
+ *maxIndex = mCache[range].maxIndex;
+
+ return mCache[range].streamOffset;
+ }
+ }
+
+ return -1;
+}
+
+void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset)
+{
+ IndexRange indexRange = {offset, count, minIndex, maxIndex, streamOffset};
+ mCache.push_back(indexRange);
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.h b/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.h
new file mode 100644
index 000000000..814f41040
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/IndexDataManager.h
@@ -0,0 +1,120 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// IndexDataManager.h: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#ifndef LIBGLESV2_INDEXDATAMANAGER_H_
+#define LIBGLESV2_INDEXDATAMANAGER_H_
+
+#include <vector>
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "libGLESv2/Context.h"
+
+namespace gl
+{
+
+struct TranslatedIndexData
+{
+ UINT minIndex;
+ UINT maxIndex;
+ UINT startIndex;
+
+ IDirect3DIndexBuffer9 *indexBuffer;
+};
+
+class IndexBuffer
+{
+ public:
+ IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format);
+ virtual ~IndexBuffer();
+
+ UINT size() const { return mBufferSize; }
+ virtual void *map(UINT requiredSpace, UINT *offset) = 0;
+ void unmap();
+ virtual void reserveSpace(UINT requiredSpace, GLenum type) = 0;
+
+ IDirect3DIndexBuffer9 *getBuffer() const;
+
+ protected:
+ IDirect3DDevice9 *const mDevice;
+
+ IDirect3DIndexBuffer9 *mIndexBuffer;
+ UINT mBufferSize;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexBuffer);
+};
+
+class StreamingIndexBuffer : public IndexBuffer
+{
+ public:
+ StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format);
+ ~StreamingIndexBuffer();
+
+ virtual void *map(UINT requiredSpace, UINT *offset);
+ virtual void reserveSpace(UINT requiredSpace, GLenum type);
+
+ private:
+ UINT mWritePosition;
+};
+
+class StaticIndexBuffer : public IndexBuffer
+{
+ public:
+ explicit StaticIndexBuffer(IDirect3DDevice9 *device);
+ ~StaticIndexBuffer();
+
+ virtual void *map(UINT requiredSpace, UINT *offset);
+ virtual void reserveSpace(UINT requiredSpace, GLenum type);
+
+ bool lookupType(GLenum type);
+ UINT lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex); // Returns the offset into the index buffer, or -1 if not found
+ void addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset);
+
+ private:
+ GLenum mCacheType;
+
+ struct IndexRange
+ {
+ intptr_t offset;
+ GLsizei count;
+
+ UINT minIndex;
+ UINT maxIndex;
+ UINT streamOffset;
+ };
+
+ std::vector<IndexRange> mCache;
+};
+
+class IndexDataManager
+{
+ public:
+ IndexDataManager(Context *context, IDirect3DDevice9 *evice);
+ virtual ~IndexDataManager();
+
+ GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexDataManager);
+
+ std::size_t typeSize(GLenum type) const;
+ std::size_t indexSize(D3DFORMAT format) const;
+
+ IDirect3DDevice9 *const mDevice;
+
+ StreamingIndexBuffer *mStreamingBufferShort;
+ StreamingIndexBuffer *mStreamingBufferInt;
+};
+
+}
+
+#endif // LIBGLESV2_INDEXDATAMANAGER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Program.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Program.cpp
new file mode 100644
index 000000000..0a25bc2af
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Program.cpp
@@ -0,0 +1,3021 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Program.cpp: Implements the gl::Program class. Implements GL program objects
+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
+
+#include "libGLESv2/Program.h"
+
+#include "common/debug.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/Shader.h"
+#include "libGLESv2/utilities.h"
+
+#include <string>
+
+#if !defined(ANGLE_COMPILE_OPTIMIZATION_LEVEL)
+#define ANGLE_COMPILE_OPTIMIZATION_LEVEL D3DCOMPILE_OPTIMIZATION_LEVEL3
+#endif
+
+namespace gl
+{
+unsigned int Program::mCurrentSerial = 1;
+
+std::string str(int i)
+{
+ char buffer[20];
+ sprintf(buffer, "%d", i);
+ return buffer;
+}
+
+Uniform::Uniform(GLenum type, const std::string &name, unsigned int arraySize) : type(type), name(name), arraySize(arraySize)
+{
+ int bytes = UniformTypeSize(type) * arraySize;
+ data = new unsigned char[bytes];
+ memset(data, 0, bytes);
+ dirty = true;
+ handlesSet = false;
+}
+
+Uniform::~Uniform()
+{
+ delete[] data;
+}
+
+UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
+ : name(name), element(element), index(index)
+{
+}
+
+Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
+{
+ mFragmentShader = NULL;
+ mVertexShader = NULL;
+
+ mPixelExecutable = NULL;
+ mVertexExecutable = NULL;
+ mConstantTablePS = NULL;
+ mConstantTableVS = NULL;
+
+ mInfoLog = NULL;
+ mValidated = false;
+
+ unlink();
+
+ mDeleteStatus = false;
+
+ mRefCount = 0;
+}
+
+Program::~Program()
+{
+ unlink(true);
+
+ if (mVertexShader != NULL)
+ {
+ mVertexShader->release();
+ }
+
+ if (mFragmentShader != NULL)
+ {
+ mFragmentShader->release();
+ }
+}
+
+bool Program::attachShader(Shader *shader)
+{
+ if (shader->getType() == GL_VERTEX_SHADER)
+ {
+ if (mVertexShader)
+ {
+ return false;
+ }
+
+ mVertexShader = (VertexShader*)shader;
+ mVertexShader->addRef();
+ }
+ else if (shader->getType() == GL_FRAGMENT_SHADER)
+ {
+ if (mFragmentShader)
+ {
+ return false;
+ }
+
+ mFragmentShader = (FragmentShader*)shader;
+ mFragmentShader->addRef();
+ }
+ else UNREACHABLE();
+
+ return true;
+}
+
+bool Program::detachShader(Shader *shader)
+{
+ if (shader->getType() == GL_VERTEX_SHADER)
+ {
+ if (mVertexShader != shader)
+ {
+ return false;
+ }
+
+ mVertexShader->release();
+ mVertexShader = NULL;
+ }
+ else if (shader->getType() == GL_FRAGMENT_SHADER)
+ {
+ if (mFragmentShader != shader)
+ {
+ return false;
+ }
+
+ mFragmentShader->release();
+ mFragmentShader = NULL;
+ }
+ else UNREACHABLE();
+
+ unlink();
+
+ return true;
+}
+
+int Program::getAttachedShadersCount() const
+{
+ return (mVertexShader ? 1 : 0) + (mFragmentShader ? 1 : 0);
+}
+
+IDirect3DPixelShader9 *Program::getPixelShader()
+{
+ return mPixelExecutable;
+}
+
+IDirect3DVertexShader9 *Program::getVertexShader()
+{
+ return mVertexExecutable;
+}
+
+void Program::bindAttributeLocation(GLuint index, const char *name)
+{
+ if (index < MAX_VERTEX_ATTRIBS)
+ {
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mAttributeBinding[i].erase(name);
+ }
+
+ mAttributeBinding[index].insert(name);
+ }
+}
+
+GLuint Program::getAttributeLocation(const char *name)
+{
+ if (name)
+ {
+ for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+ {
+ if (mLinkedAttribute[index].name == std::string(name))
+ {
+ return index;
+ }
+ }
+ }
+
+ return -1;
+}
+
+int Program::getSemanticIndex(int attributeIndex)
+{
+ ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
+
+ return mSemanticIndex[attributeIndex];
+}
+
+// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
+// index (0-15 for the pixel shader and 0-3 for the vertex shader).
+GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
+{
+ GLuint logicalTextureUnit = -1;
+
+ switch (type)
+ {
+ case SAMPLER_PIXEL:
+ ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
+
+ if (mSamplersPS[samplerIndex].active)
+ {
+ logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
+ }
+ break;
+ case SAMPLER_VERTEX:
+ ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
+
+ if (mSamplersVS[samplerIndex].active)
+ {
+ logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ if (logicalTextureUnit >= 0 && logicalTextureUnit < getContext()->getMaximumCombinedTextureImageUnits())
+ {
+ return logicalTextureUnit;
+ }
+
+ return -1;
+}
+
+// Returns the texture type for a given Direct3D 9 sampler type and
+// index (0-15 for the pixel shader and 0-3 for the vertex shader).
+TextureType Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
+{
+ switch (type)
+ {
+ case SAMPLER_PIXEL:
+ ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
+ ASSERT(mSamplersPS[samplerIndex].active);
+ return mSamplersPS[samplerIndex].textureType;
+ case SAMPLER_VERTEX:
+ ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
+ ASSERT(mSamplersVS[samplerIndex].active);
+ return mSamplersVS[samplerIndex].textureType;
+ default: UNREACHABLE();
+ }
+
+ return TEXTURE_2D;
+}
+
+GLint Program::getUniformLocation(const char *name, bool decorated)
+{
+ std::string _name = decorated ? name : decorate(name);
+ int subscript = 0;
+
+ // Strip any trailing array operator and retrieve the subscript
+ size_t open = _name.find_last_of('[');
+ size_t close = _name.find_last_of(']');
+ if (open != std::string::npos && close == _name.length() - 1)
+ {
+ subscript = atoi(_name.substr(open + 1).c_str());
+ _name.erase(open);
+ }
+
+ unsigned int numUniforms = mUniformIndex.size();
+ for (unsigned int location = 0; location < numUniforms; location++)
+ {
+ if (mUniformIndex[location].name == _name &&
+ mUniformIndex[location].element == subscript)
+ {
+ return location;
+ }
+ }
+
+ return -1;
+}
+
+bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type == GL_FLOAT)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat),
+ v, sizeof(GLfloat) * count);
+ }
+ else if (targetUniform->type == GL_BOOL)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+ GLboolean *boolParams = new GLboolean[count];
+
+ for (int i = 0; i < count; ++i)
+ {
+ if (v[i] == 0.0f)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
+ boolParams, sizeof(GLboolean) * count);
+
+ delete [] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type == GL_FLOAT_VEC2)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 2,
+ v, 2 * sizeof(GLfloat) * count);
+ }
+ else if (targetUniform->type == GL_BOOL_VEC2)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ GLboolean *boolParams = new GLboolean[count * 2];
+
+ for (int i = 0; i < count * 2; ++i)
+ {
+ if (v[i] == 0.0f)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
+ boolParams, 2 * sizeof(GLboolean) * count);
+
+ delete [] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type == GL_FLOAT_VEC3)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 3,
+ v, 3 * sizeof(GLfloat) * count);
+ }
+ else if (targetUniform->type == GL_BOOL_VEC3)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+ GLboolean *boolParams = new GLboolean[count * 3];
+
+ for (int i = 0; i < count * 3; ++i)
+ {
+ if (v[i] == 0.0f)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
+ boolParams, 3 * sizeof(GLboolean) * count);
+
+ delete [] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type == GL_FLOAT_VEC4)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
+ v, 4 * sizeof(GLfloat) * count);
+ }
+ else if (targetUniform->type == GL_BOOL_VEC4)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+ GLboolean *boolParams = new GLboolean[count * 4];
+
+ for (int i = 0; i < count * 4; ++i)
+ {
+ if (v[i] == 0.0f)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
+ boolParams, 4 * sizeof(GLboolean) * count);
+
+ delete [] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type != GL_FLOAT_MAT2)
+ {
+ return false;
+ }
+
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 4,
+ value, 4 * sizeof(GLfloat) * count);
+
+ return true;
+}
+
+bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type != GL_FLOAT_MAT3)
+ {
+ return false;
+ }
+
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 9,
+ value, 9 * sizeof(GLfloat) * count);
+
+ return true;
+}
+
+bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type != GL_FLOAT_MAT4)
+ {
+ return false;
+ }
+
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16,
+ value, 16 * sizeof(GLfloat) * count);
+
+ return true;
+}
+
+bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type == GL_INT ||
+ targetUniform->type == GL_SAMPLER_2D ||
+ targetUniform->type == GL_SAMPLER_CUBE)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint),
+ v, sizeof(GLint) * count);
+ }
+ else if (targetUniform->type == GL_BOOL)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+ GLboolean *boolParams = new GLboolean[count];
+
+ for (int i = 0; i < count; ++i)
+ {
+ if (v[i] == 0)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean),
+ boolParams, sizeof(GLboolean) * count);
+
+ delete [] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type == GL_INT_VEC2)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 2,
+ v, 2 * sizeof(GLint) * count);
+ }
+ else if (targetUniform->type == GL_BOOL_VEC2)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+ GLboolean *boolParams = new GLboolean[count * 2];
+
+ for (int i = 0; i < count * 2; ++i)
+ {
+ if (v[i] == 0)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 2,
+ boolParams, 2 * sizeof(GLboolean) * count);
+
+ delete [] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type == GL_INT_VEC3)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 3,
+ v, 3 * sizeof(GLint) * count);
+ }
+ else if (targetUniform->type == GL_BOOL_VEC3)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+ GLboolean *boolParams = new GLboolean[count * 3];
+
+ for (int i = 0; i < count * 3; ++i)
+ {
+ if (v[i] == 0)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 3,
+ boolParams, 3 * sizeof(GLboolean) * count);
+
+ delete [] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+ targetUniform->dirty = true;
+
+ if (targetUniform->type == GL_INT_VEC4)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLint) * 4,
+ v, 4 * sizeof(GLint) * count);
+ }
+ else if (targetUniform->type == GL_BOOL_VEC4)
+ {
+ int arraySize = targetUniform->arraySize;
+
+ if (arraySize == 1 && count > 1)
+ return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+
+ count = std::min(arraySize - (int)mUniformIndex[location].element, count);
+ GLboolean *boolParams = new GLboolean[count * 4];
+
+ for (int i = 0; i < count * 4; ++i)
+ {
+ if (v[i] == 0)
+ {
+ boolParams[i] = GL_FALSE;
+ }
+ else
+ {
+ boolParams[i] = GL_TRUE;
+ }
+ }
+
+ memcpy(targetUniform->data + mUniformIndex[location].element * sizeof(GLboolean) * 4,
+ boolParams, 4 * sizeof(GLboolean) * count);
+
+ delete [] boolParams;
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+bool Program::getUniformfv(GLint location, GLfloat *params)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ unsigned int count = UniformComponentCount(targetUniform->type);
+
+ switch (UniformComponentType(targetUniform->type))
+ {
+ case GL_BOOL:
+ {
+ GLboolean *boolParams = (GLboolean*)targetUniform->data + mUniformIndex[location].element * count;
+
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
+ }
+ }
+ break;
+ case GL_FLOAT:
+ memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLfloat),
+ count * sizeof(GLfloat));
+ break;
+ case GL_INT:
+ {
+ GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * count;
+
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ params[i] = (float)intParams[i];
+ }
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+bool Program::getUniformiv(GLint location, GLint *params)
+{
+ if (location < 0 || location >= (int)mUniformIndex.size())
+ {
+ return false;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ unsigned int count = UniformComponentCount(targetUniform->type);
+
+ switch (UniformComponentType(targetUniform->type))
+ {
+ case GL_BOOL:
+ {
+ GLboolean *boolParams = targetUniform->data + mUniformIndex[location].element * count;
+
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ params[i] = (GLint)boolParams[i];
+ }
+ }
+ break;
+ case GL_FLOAT:
+ {
+ GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * count;
+
+ for (unsigned int i = 0; i < count; ++i)
+ {
+ params[i] = (GLint)floatParams[i];
+ }
+ }
+ break;
+ case GL_INT:
+ memcpy(params, targetUniform->data + mUniformIndex[location].element * count * sizeof(GLint),
+ count * sizeof(GLint));
+ break;
+ default: UNREACHABLE();
+ }
+
+ return true;
+}
+
+void Program::dirtyAllUniforms()
+{
+ unsigned int numUniforms = mUniforms.size();
+ for (unsigned int index = 0; index < numUniforms; index++)
+ {
+ mUniforms[index]->dirty = true;
+ }
+}
+
+// Applies all the uniforms set for this program object to the Direct3D 9 device
+void Program::applyUniforms()
+{
+ unsigned int numUniforms = mUniformIndex.size();
+ for (unsigned int location = 0; location < numUniforms; location++)
+ {
+ if (mUniformIndex[location].element != 0)
+ {
+ continue;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ if (targetUniform->dirty)
+ {
+ int arraySize = targetUniform->arraySize;
+ GLfloat *f = (GLfloat*)targetUniform->data;
+ GLint *i = (GLint*)targetUniform->data;
+ GLboolean *b = (GLboolean*)targetUniform->data;
+
+ switch (targetUniform->type)
+ {
+ case GL_BOOL: applyUniform1bv(location, arraySize, b); break;
+ case GL_BOOL_VEC2: applyUniform2bv(location, arraySize, b); break;
+ case GL_BOOL_VEC3: applyUniform3bv(location, arraySize, b); break;
+ case GL_BOOL_VEC4: applyUniform4bv(location, arraySize, b); break;
+ case GL_FLOAT: applyUniform1fv(location, arraySize, f); break;
+ case GL_FLOAT_VEC2: applyUniform2fv(location, arraySize, f); break;
+ case GL_FLOAT_VEC3: applyUniform3fv(location, arraySize, f); break;
+ case GL_FLOAT_VEC4: applyUniform4fv(location, arraySize, f); break;
+ case GL_FLOAT_MAT2: applyUniformMatrix2fv(location, arraySize, f); break;
+ case GL_FLOAT_MAT3: applyUniformMatrix3fv(location, arraySize, f); break;
+ case GL_FLOAT_MAT4: applyUniformMatrix4fv(location, arraySize, f); break;
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_INT: applyUniform1iv(location, arraySize, i); break;
+ case GL_INT_VEC2: applyUniform2iv(location, arraySize, i); break;
+ case GL_INT_VEC3: applyUniform3iv(location, arraySize, i); break;
+ case GL_INT_VEC4: applyUniform4iv(location, arraySize, i); break;
+ default:
+ UNREACHABLE();
+ }
+
+ targetUniform->dirty = false;
+ }
+ }
+}
+
+// Compiles the HLSL code of the attached shaders into executable binaries
+ID3D10Blob *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
+{
+ if (!hlsl)
+ {
+ return NULL;
+ }
+
+ DWORD result;
+ UINT flags = 0;
+ std::string sourceText;
+ if (perfActive())
+ {
+ flags |= D3DCOMPILE_DEBUG;
+#ifdef NDEBUG
+ flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
+#else
+ flags |= D3DCOMPILE_SKIP_OPTIMIZATION;
+#endif
+
+ std::string sourcePath = getTempPath();
+ sourceText = std::string("#line 2 \"") + sourcePath + std::string("\"\n\n") + std::string(hlsl);
+ writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
+ }
+ else
+ {
+ flags |= ANGLE_COMPILE_OPTIMIZATION_LEVEL;
+ sourceText = hlsl;
+ }
+
+ ID3D10Blob *binary = NULL;
+ ID3D10Blob *errorMessage = NULL;
+ result = D3DCompile(hlsl, strlen(hlsl), NULL, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
+
+ if (errorMessage)
+ {
+ const char *message = (const char*)errorMessage->GetBufferPointer();
+
+ appendToInfoLogSanitized(message);
+ TRACE("\n%s", hlsl);
+ TRACE("\n%s", message);
+
+ errorMessage->Release();
+ errorMessage = NULL;
+ }
+
+
+ if (FAILED(result))
+ {
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ error(GL_OUT_OF_MEMORY);
+ }
+
+ return NULL;
+ }
+
+ result = D3DXGetShaderConstantTable(static_cast<const DWORD*>(binary->GetBufferPointer()), constantTable);
+
+ if (FAILED(result))
+ {
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ error(GL_OUT_OF_MEMORY);
+ }
+
+ binary->Release();
+
+ return NULL;
+ }
+
+ return binary;
+}
+
+// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
+// Returns the number of used varying registers, or -1 if unsuccesful
+int Program::packVaryings(const Varying *packing[][4])
+{
+ Context *context = getContext();
+ const int maxVaryingVectors = context->getMaximumVaryingVectors();
+
+ for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
+ {
+ int n = VariableRowCount(varying->type) * varying->size;
+ int m = VariableColumnCount(varying->type);
+ bool success = false;
+
+ if (m == 2 || m == 3 || m == 4)
+ {
+ for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
+ {
+ bool available = true;
+
+ for (int y = 0; y < n && available; y++)
+ {
+ for (int x = 0; x < m && available; x++)
+ {
+ if (packing[r + y][x])
+ {
+ available = false;
+ }
+ }
+ }
+
+ if (available)
+ {
+ varying->reg = r;
+ varying->col = 0;
+
+ for (int y = 0; y < n; y++)
+ {
+ for (int x = 0; x < m; x++)
+ {
+ packing[r + y][x] = &*varying;
+ }
+ }
+
+ success = true;
+ }
+ }
+
+ if (!success && m == 2)
+ {
+ for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
+ {
+ bool available = true;
+
+ for (int y = 0; y < n && available; y++)
+ {
+ for (int x = 2; x < 4 && available; x++)
+ {
+ if (packing[r + y][x])
+ {
+ available = false;
+ }
+ }
+ }
+
+ if (available)
+ {
+ varying->reg = r;
+ varying->col = 2;
+
+ for (int y = 0; y < n; y++)
+ {
+ for (int x = 2; x < 4; x++)
+ {
+ packing[r + y][x] = &*varying;
+ }
+ }
+
+ success = true;
+ }
+ }
+ }
+ }
+ else if (m == 1)
+ {
+ int space[4] = {0};
+
+ for (int y = 0; y < maxVaryingVectors; y++)
+ {
+ for (int x = 0; x < 4; x++)
+ {
+ space[x] += packing[y][x] ? 0 : 1;
+ }
+ }
+
+ int column = 0;
+
+ for (int x = 0; x < 4; x++)
+ {
+ if (space[x] >= n && space[x] < space[column])
+ {
+ column = x;
+ }
+ }
+
+ if (space[column] >= n)
+ {
+ for (int r = 0; r < maxVaryingVectors; r++)
+ {
+ if (!packing[r][column])
+ {
+ varying->reg = r;
+
+ for (int y = r; y < r + n; y++)
+ {
+ packing[y][column] = &*varying;
+ }
+
+ break;
+ }
+ }
+
+ varying->col = column;
+
+ success = true;
+ }
+ }
+ else UNREACHABLE();
+
+ if (!success)
+ {
+ appendToInfoLog("Could not pack varying %s", varying->name.c_str());
+
+ return -1;
+ }
+ }
+
+ // Return the number of used registers
+ int registers = 0;
+
+ for (int r = 0; r < maxVaryingVectors; r++)
+ {
+ if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
+ {
+ registers++;
+ }
+ }
+
+ return registers;
+}
+
+bool Program::linkVaryings()
+{
+ if (mPixelHLSL.empty() || mVertexHLSL.empty())
+ {
+ return false;
+ }
+
+ // Reset the varying register assignments
+ for (VaryingList::iterator fragVar = mFragmentShader->varyings.begin(); fragVar != mFragmentShader->varyings.end(); fragVar++)
+ {
+ fragVar->reg = -1;
+ fragVar->col = -1;
+ }
+
+ for (VaryingList::iterator vtxVar = mVertexShader->varyings.begin(); vtxVar != mVertexShader->varyings.end(); vtxVar++)
+ {
+ vtxVar->reg = -1;
+ vtxVar->col = -1;
+ }
+
+ // Map the varyings to the register file
+ const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
+ int registers = packVaryings(packing);
+
+ if (registers < 0)
+ {
+ return false;
+ }
+
+ // Write the HLSL input/output declarations
+ Context *context = getContext();
+ const bool sm3 = context->supportsShaderModel3();
+ const int maxVaryingVectors = context->getMaximumVaryingVectors();
+
+ if (registers == maxVaryingVectors && mFragmentShader->mUsesFragCoord)
+ {
+ appendToInfoLog("No varying registers left to support gl_FragCoord");
+
+ return false;
+ }
+
+ for (VaryingList::iterator input = mFragmentShader->varyings.begin(); input != mFragmentShader->varyings.end(); input++)
+ {
+ bool matched = false;
+
+ for (VaryingList::iterator output = mVertexShader->varyings.begin(); output != mVertexShader->varyings.end(); output++)
+ {
+ if (output->name == input->name)
+ {
+ if (output->type != input->type || output->size != input->size)
+ {
+ appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
+
+ return false;
+ }
+
+ output->reg = input->reg;
+ output->col = input->col;
+
+ matched = true;
+ break;
+ }
+ }
+
+ if (!matched)
+ {
+ appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
+
+ return false;
+ }
+ }
+
+ std::string varyingSemantic = (sm3 ? "COLOR" : "TEXCOORD");
+
+ mVertexHLSL += "struct VS_INPUT\n"
+ "{\n";
+
+ int semanticIndex = 0;
+ for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
+ {
+ switch (attribute->type)
+ {
+ case GL_FLOAT: mVertexHLSL += " float "; break;
+ case GL_FLOAT_VEC2: mVertexHLSL += " float2 "; break;
+ case GL_FLOAT_VEC3: mVertexHLSL += " float3 "; break;
+ case GL_FLOAT_VEC4: mVertexHLSL += " float4 "; break;
+ case GL_FLOAT_MAT2: mVertexHLSL += " float2x2 "; break;
+ case GL_FLOAT_MAT3: mVertexHLSL += " float3x3 "; break;
+ case GL_FLOAT_MAT4: mVertexHLSL += " float4x4 "; break;
+ default: UNREACHABLE();
+ }
+
+ mVertexHLSL += decorate(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
+
+ semanticIndex += VariableRowCount(attribute->type);
+ }
+
+ mVertexHLSL += "};\n"
+ "\n"
+ "struct VS_OUTPUT\n"
+ "{\n"
+ " float4 gl_Position : POSITION;\n";
+
+ for (int r = 0; r < registers; r++)
+ {
+ int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
+
+ mVertexHLSL += " float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
+ }
+
+ if (mFragmentShader->mUsesFragCoord)
+ {
+ mVertexHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
+ }
+
+ if (mVertexShader->mUsesPointSize && sm3)
+ {
+ mVertexHLSL += " float gl_PointSize : PSIZE;\n";
+ }
+
+ mVertexHLSL += "};\n"
+ "\n"
+ "VS_OUTPUT main(VS_INPUT input)\n"
+ "{\n";
+
+ for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
+ {
+ mVertexHLSL += " " + decorate(attribute->name) + " = ";
+
+ if (VariableRowCount(attribute->type) > 1) // Matrix
+ {
+ mVertexHLSL += "transpose";
+ }
+
+ mVertexHLSL += "(input." + decorate(attribute->name) + ");\n";
+ }
+
+ mVertexHLSL += "\n"
+ " gl_main();\n"
+ "\n"
+ " VS_OUTPUT output;\n"
+ " output.gl_Position.x = gl_Position.x - dx_HalfPixelSize.x * gl_Position.w;\n"
+ " output.gl_Position.y = gl_Position.y - dx_HalfPixelSize.y * gl_Position.w;\n"
+ " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
+ " output.gl_Position.w = gl_Position.w;\n";
+
+ if (mVertexShader->mUsesPointSize && sm3)
+ {
+ mVertexHLSL += " output.gl_PointSize = clamp(gl_PointSize, 1.0, " + str((int)ALIASED_POINT_SIZE_RANGE_MAX_SM3) + ");\n";
+ }
+
+ if (mFragmentShader->mUsesFragCoord)
+ {
+ mVertexHLSL += " output.gl_FragCoord = gl_Position;\n";
+ }
+
+ for (VaryingList::iterator varying = mVertexShader->varyings.begin(); varying != mVertexShader->varyings.end(); varying++)
+ {
+ if (varying->reg >= 0)
+ {
+ for (int i = 0; i < varying->size; i++)
+ {
+ int rows = VariableRowCount(varying->type);
+
+ for (int j = 0; j < rows; j++)
+ {
+ int r = varying->reg + i * rows + j;
+ mVertexHLSL += " output.v" + str(r);
+
+ bool sharedRegister = false; // Register used by multiple varyings
+
+ for (int x = 0; x < 4; x++)
+ {
+ if (packing[r][x] && packing[r][x] != packing[r][0])
+ {
+ sharedRegister = true;
+ break;
+ }
+ }
+
+ if(sharedRegister)
+ {
+ mVertexHLSL += ".";
+
+ for (int x = 0; x < 4; x++)
+ {
+ if (packing[r][x] == &*varying)
+ {
+ switch(x)
+ {
+ case 0: mVertexHLSL += "x"; break;
+ case 1: mVertexHLSL += "y"; break;
+ case 2: mVertexHLSL += "z"; break;
+ case 3: mVertexHLSL += "w"; break;
+ }
+ }
+ }
+ }
+
+ mVertexHLSL += " = " + varying->name;
+
+ if (varying->array)
+ {
+ mVertexHLSL += "[" + str(i) + "]";
+ }
+
+ if (rows > 1)
+ {
+ mVertexHLSL += "[" + str(j) + "]";
+ }
+
+ mVertexHLSL += ";\n";
+ }
+ }
+ }
+ }
+
+ mVertexHLSL += "\n"
+ " return output;\n"
+ "}\n";
+
+ mPixelHLSL += "struct PS_INPUT\n"
+ "{\n";
+
+ for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
+ {
+ if (varying->reg >= 0)
+ {
+ for (int i = 0; i < varying->size; i++)
+ {
+ int rows = VariableRowCount(varying->type);
+ for (int j = 0; j < rows; j++)
+ {
+ std::string n = str(varying->reg + i * rows + j);
+ mPixelHLSL += " float4 v" + n + " : " + varyingSemantic + n + ";\n";
+ }
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ if (mFragmentShader->mUsesFragCoord)
+ {
+ mPixelHLSL += " float4 gl_FragCoord : " + varyingSemantic + str(registers) + ";\n";
+ if (sm3) {
+ mPixelHLSL += " float2 dx_VPos : VPOS;\n";
+ }
+ }
+
+ if (mFragmentShader->mUsesPointCoord && sm3)
+ {
+ mPixelHLSL += " float2 gl_PointCoord : TEXCOORD0;\n";
+ }
+
+ if (mFragmentShader->mUsesFrontFacing)
+ {
+ mPixelHLSL += " float vFace : VFACE;\n";
+ }
+
+ mPixelHLSL += "};\n"
+ "\n"
+ "struct PS_OUTPUT\n"
+ "{\n"
+ " float4 gl_Color[1] : COLOR;\n"
+ "};\n"
+ "\n"
+ "PS_OUTPUT main(PS_INPUT input)\n"
+ "{\n";
+
+ if (mFragmentShader->mUsesFragCoord)
+ {
+ mPixelHLSL += " float rhw = 1.0 / input.gl_FragCoord.w;\n";
+ if (sm3) {
+ mPixelHLSL += " gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
+ " gl_FragCoord.y = 2.0 * dx_Viewport.y - input.dx_VPos.y - 0.5;\n";
+ } else {
+ mPixelHLSL += " gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_Viewport.x + dx_Viewport.z;\n"
+ " gl_FragCoord.y = -(input.gl_FragCoord.y * rhw) * dx_Viewport.y + dx_Viewport.w;\n";
+ }
+ mPixelHLSL += " gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_Depth.x + dx_Depth.y;\n"
+ " gl_FragCoord.w = rhw;\n";
+ }
+
+ if (mFragmentShader->mUsesPointCoord && sm3)
+ {
+ mPixelHLSL += " gl_PointCoord = input.gl_PointCoord;\n";
+ }
+
+ if (mFragmentShader->mUsesFrontFacing)
+ {
+ mPixelHLSL += " gl_FrontFacing = dx_PointsOrLines || (dx_FrontCCW ? (input.vFace >= 0.0) : (input.vFace <= 0.0));\n";
+ }
+
+ for (VaryingList::iterator varying = mFragmentShader->varyings.begin(); varying != mFragmentShader->varyings.end(); varying++)
+ {
+ if (varying->reg >= 0)
+ {
+ for (int i = 0; i < varying->size; i++)
+ {
+ int rows = VariableRowCount(varying->type);
+ for (int j = 0; j < rows; j++)
+ {
+ std::string n = str(varying->reg + i * rows + j);
+ mPixelHLSL += " " + varying->name;
+
+ if (varying->array)
+ {
+ mPixelHLSL += "[" + str(i) + "]";
+ }
+
+ if (rows > 1)
+ {
+ mPixelHLSL += "[" + str(j) + "]";
+ }
+
+ mPixelHLSL += " = input.v" + n + ";\n";
+ }
+ }
+ }
+ else UNREACHABLE();
+ }
+
+ mPixelHLSL += "\n"
+ " gl_main();\n"
+ "\n"
+ " PS_OUTPUT output;\n"
+ " output.gl_Color[0] = gl_Color[0];\n"
+ "\n"
+ " return output;\n"
+ "}\n";
+
+ return true;
+}
+
+// Links the HLSL code of the vertex and pixel shader by matching up their varyings,
+// compiling them into binaries, determining the attribute mappings, and collecting
+// a list of uniforms
+void Program::link()
+{
+ unlink();
+
+ if (!mFragmentShader || !mFragmentShader->isCompiled())
+ {
+ return;
+ }
+
+ if (!mVertexShader || !mVertexShader->isCompiled())
+ {
+ return;
+ }
+
+ mPixelHLSL = mFragmentShader->getHLSL();
+ mVertexHLSL = mVertexShader->getHLSL();
+
+ if (!linkVaryings())
+ {
+ return;
+ }
+
+ Context *context = getContext();
+ const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
+ const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
+
+ ID3D10Blob *vertexBinary = compileToBinary(mVertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
+ ID3D10Blob *pixelBinary = compileToBinary(mPixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
+
+ if (vertexBinary && pixelBinary)
+ {
+ IDirect3DDevice9 *device = getDevice();
+ HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable);
+ HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable);
+
+ if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult));
+
+ vertexBinary->Release();
+ pixelBinary->Release();
+ vertexBinary = NULL;
+ pixelBinary = NULL;
+
+ if (mVertexExecutable && mPixelExecutable)
+ {
+ if (!linkAttributes())
+ {
+ return;
+ }
+
+ if (!linkUniforms(mConstantTablePS))
+ {
+ return;
+ }
+
+ if (!linkUniforms(mConstantTableVS))
+ {
+ return;
+ }
+
+ // these uniforms are searched as already-decorated because gl_ and dx_
+ // are reserved prefixes, and do not receive additional decoration
+ mDxDepthRangeLocation = getUniformLocation("dx_DepthRange", true);
+ mDxDepthLocation = getUniformLocation("dx_Depth", true);
+ mDxViewportLocation = getUniformLocation("dx_Viewport", true);
+ mDxHalfPixelSizeLocation = getUniformLocation("dx_HalfPixelSize", true);
+ mDxFrontCCWLocation = getUniformLocation("dx_FrontCCW", true);
+ mDxPointsOrLinesLocation = getUniformLocation("dx_PointsOrLines", true);
+
+ mLinked = true; // Success
+ }
+ }
+}
+
+// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
+bool Program::linkAttributes()
+{
+ unsigned int usedLocations = 0;
+
+ // Link attributes that have a binding location
+ for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
+ {
+ int location = getAttributeBinding(attribute->name);
+
+ if (location != -1) // Set by glBindAttribLocation
+ {
+ if (!mLinkedAttribute[location].name.empty())
+ {
+ // Multiple active attributes bound to the same location; not an error
+ }
+
+ mLinkedAttribute[location] = *attribute;
+
+ int rows = VariableRowCount(attribute->type);
+
+ if (rows + location > MAX_VERTEX_ATTRIBS)
+ {
+ appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
+
+ return false;
+ }
+
+ for (int i = 0; i < rows; i++)
+ {
+ usedLocations |= 1 << (location + i);
+ }
+ }
+ }
+
+ // Link attributes that don't have a binding location
+ for (AttributeArray::iterator attribute = mVertexShader->mAttributes.begin(); attribute != mVertexShader->mAttributes.end(); attribute++)
+ {
+ int location = getAttributeBinding(attribute->name);
+
+ if (location == -1) // Not set by glBindAttribLocation
+ {
+ int rows = VariableRowCount(attribute->type);
+ int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
+
+ if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
+ {
+ appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
+
+ return false; // Fail to link
+ }
+
+ mLinkedAttribute[availableIndex] = *attribute;
+ }
+ }
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
+ {
+ int index = mVertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
+ int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
+
+ for (int r = 0; r < rows; r++)
+ {
+ mSemanticIndex[attributeIndex++] = index++;
+ }
+ }
+
+ return true;
+}
+
+int Program::getAttributeBinding(const std::string &name)
+{
+ for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
+ {
+ if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
+ {
+ return location;
+ }
+ }
+
+ return -1;
+}
+
+bool Program::linkUniforms(ID3DXConstantTable *constantTable)
+{
+ D3DXCONSTANTTABLE_DESC constantTableDescription;
+ D3DXCONSTANT_DESC constantDescription;
+ UINT descriptionCount = 1;
+
+ constantTable->GetDesc(&constantTableDescription);
+
+ for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++)
+ {
+ D3DXHANDLE constantHandle = constantTable->GetConstant(0, constantIndex);
+ HRESULT result = constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
+ ASSERT(SUCCEEDED(result));
+
+ if (!defineUniform(constantHandle, constantDescription))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Adds the description of a constant found in the binary shader to the list of uniforms
+// Returns true if succesful (uniform not already defined)
+bool Program::defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
+{
+ if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
+ {
+ for (unsigned int samplerIndex = constantDescription.RegisterIndex; samplerIndex < constantDescription.RegisterIndex + constantDescription.RegisterCount; samplerIndex++)
+ {
+ if (mConstantTablePS->GetConstantByName(NULL, constantDescription.Name) != NULL)
+ {
+ if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
+ {
+ mSamplersPS[samplerIndex].active = true;
+ mSamplersPS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
+ mSamplersPS[samplerIndex].logicalTextureUnit = 0;
+ }
+ else
+ {
+ appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
+ return false;
+ }
+ }
+
+ if (mConstantTableVS->GetConstantByName(NULL, constantDescription.Name) != NULL)
+ {
+ if (samplerIndex < getContext()->getMaximumVertexTextureImageUnits())
+ {
+ mSamplersVS[samplerIndex].active = true;
+ mSamplersVS[samplerIndex].textureType = (constantDescription.Type == D3DXPT_SAMPLERCUBE) ? TEXTURE_CUBE : TEXTURE_2D;
+ mSamplersVS[samplerIndex].logicalTextureUnit = 0;
+ }
+ else
+ {
+ appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
+ return false;
+ }
+ }
+ }
+ }
+
+ switch(constantDescription.Class)
+ {
+ case D3DXPC_STRUCT:
+ {
+ for (unsigned int arrayIndex = 0; arrayIndex < constantDescription.Elements; arrayIndex++)
+ {
+ for (unsigned int field = 0; field < constantDescription.StructMembers; field++)
+ {
+ D3DXHANDLE fieldHandle = mConstantTablePS->GetConstant(constantHandle, field);
+
+ D3DXCONSTANT_DESC fieldDescription;
+ UINT descriptionCount = 1;
+
+ HRESULT result = mConstantTablePS->GetConstantDesc(fieldHandle, &fieldDescription, &descriptionCount);
+ ASSERT(SUCCEEDED(result));
+
+ std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
+
+ if (!defineUniform(fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+ case D3DXPC_SCALAR:
+ case D3DXPC_VECTOR:
+ case D3DXPC_MATRIX_COLUMNS:
+ case D3DXPC_OBJECT:
+ return defineUniform(constantDescription, name + constantDescription.Name);
+ default:
+ UNREACHABLE();
+ return false;
+ }
+}
+
+bool Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
+{
+ Uniform *uniform = createUniform(constantDescription, name);
+
+ if(!uniform)
+ {
+ return false;
+ }
+
+ // Check if already defined
+ GLint location = getUniformLocation(name.c_str(), true);
+ GLenum type = uniform->type;
+
+ if (location >= 0)
+ {
+ delete uniform;
+
+ if (mUniforms[mUniformIndex[location].index]->type != type)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ mUniforms.push_back(uniform);
+ unsigned int uniformIndex = mUniforms.size() - 1;
+
+ for (unsigned int i = 0; i < uniform->arraySize; ++i)
+ {
+ mUniformIndex.push_back(UniformLocation(name, i, uniformIndex));
+ }
+
+ return true;
+}
+
+Uniform *Program::createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name)
+{
+ if (constantDescription.Rows == 1) // Vectors and scalars
+ {
+ switch (constantDescription.Type)
+ {
+ case D3DXPT_SAMPLER2D:
+ switch (constantDescription.Columns)
+ {
+ case 1: return new Uniform(GL_SAMPLER_2D, name, constantDescription.Elements);
+ default: UNREACHABLE();
+ }
+ break;
+ case D3DXPT_SAMPLERCUBE:
+ switch (constantDescription.Columns)
+ {
+ case 1: return new Uniform(GL_SAMPLER_CUBE, name, constantDescription.Elements);
+ default: UNREACHABLE();
+ }
+ break;
+ case D3DXPT_BOOL:
+ switch (constantDescription.Columns)
+ {
+ case 1: return new Uniform(GL_BOOL, name, constantDescription.Elements);
+ case 2: return new Uniform(GL_BOOL_VEC2, name, constantDescription.Elements);
+ case 3: return new Uniform(GL_BOOL_VEC3, name, constantDescription.Elements);
+ case 4: return new Uniform(GL_BOOL_VEC4, name, constantDescription.Elements);
+ default: UNREACHABLE();
+ }
+ break;
+ case D3DXPT_INT:
+ switch (constantDescription.Columns)
+ {
+ case 1: return new Uniform(GL_INT, name, constantDescription.Elements);
+ case 2: return new Uniform(GL_INT_VEC2, name, constantDescription.Elements);
+ case 3: return new Uniform(GL_INT_VEC3, name, constantDescription.Elements);
+ case 4: return new Uniform(GL_INT_VEC4, name, constantDescription.Elements);
+ default: UNREACHABLE();
+ }
+ break;
+ case D3DXPT_FLOAT:
+ switch (constantDescription.Columns)
+ {
+ case 1: return new Uniform(GL_FLOAT, name, constantDescription.Elements);
+ case 2: return new Uniform(GL_FLOAT_VEC2, name, constantDescription.Elements);
+ case 3: return new Uniform(GL_FLOAT_VEC3, name, constantDescription.Elements);
+ case 4: return new Uniform(GL_FLOAT_VEC4, name, constantDescription.Elements);
+ default: UNREACHABLE();
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ else if (constantDescription.Rows == constantDescription.Columns) // Square matrices
+ {
+ switch (constantDescription.Type)
+ {
+ case D3DXPT_FLOAT:
+ switch (constantDescription.Rows)
+ {
+ case 2: return new Uniform(GL_FLOAT_MAT2, name, constantDescription.Elements);
+ case 3: return new Uniform(GL_FLOAT_MAT3, name, constantDescription.Elements);
+ case 4: return new Uniform(GL_FLOAT_MAT4, name, constantDescription.Elements);
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ else UNREACHABLE();
+
+ return 0;
+}
+
+// This method needs to match OutputHLSL::decorate
+std::string Program::decorate(const std::string &string)
+{
+ if (string.substr(0, 3) != "gl_" && string.substr(0, 3) != "dx_")
+ {
+ return "_" + string;
+ }
+ else
+ {
+ return string;
+ }
+}
+
+std::string Program::undecorate(const std::string &string)
+{
+ if (string.substr(0, 1) == "_")
+ {
+ return string.substr(1);
+ }
+ else
+ {
+ return string;
+ }
+}
+
+bool Program::applyUniform1bv(GLint location, GLsizei count, const GLboolean *v)
+{
+ BOOL *vector = new BOOL[count];
+ for (int i = 0; i < count; i++)
+ {
+ if (v[i] == GL_FALSE)
+ vector[i] = 0;
+ else
+ vector[i] = 1;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetBoolArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetBoolArray(device, constantVS, vector, count);
+ }
+
+ delete [] vector;
+
+ return true;
+}
+
+bool Program::applyUniform2bv(GLint location, GLsizei count, const GLboolean *v)
+{
+ D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
+ (v[1] == GL_FALSE ? 0.0f : 1.0f), 0, 0);
+
+ v += 2;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
+ }
+
+ delete[] vector;
+
+ return true;
+}
+
+bool Program::applyUniform3bv(GLint location, GLsizei count, const GLboolean *v)
+{
+ D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
+ (v[1] == GL_FALSE ? 0.0f : 1.0f),
+ (v[2] == GL_FALSE ? 0.0f : 1.0f), 0);
+
+ v += 3;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
+ }
+
+ delete[] vector;
+
+ return true;
+}
+
+bool Program::applyUniform4bv(GLint location, GLsizei count, const GLboolean *v)
+{
+ D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ vector[i] = D3DXVECTOR4((v[0] == GL_FALSE ? 0.0f : 1.0f),
+ (v[1] == GL_FALSE ? 0.0f : 1.0f),
+ (v[2] == GL_FALSE ? 0.0f : 1.0f),
+ (v[3] == GL_FALSE ? 0.0f : 1.0f));
+
+ v += 3;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
+ }
+
+ delete [] vector;
+
+ return true;
+}
+
+bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetFloatArray(device, constantPS, v, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetFloatArray(device, constantVS, v, count);
+ }
+
+ return true;
+}
+
+bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0);
+
+ v += 2;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
+ }
+
+ delete[] vector;
+
+ return true;
+}
+
+bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0);
+
+ v += 3;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
+ }
+
+ delete[] vector;
+
+ return true;
+}
+
+bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+{
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count);
+ }
+
+ return true;
+}
+
+bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ D3DXMATRIX *matrix = new D3DXMATRIX[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0,
+ value[1], value[3], 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1);
+
+ value += 4;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
+ }
+
+ delete[] matrix;
+
+ return true;
+}
+
+bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ D3DXMATRIX *matrix = new D3DXMATRIX[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0,
+ value[1], value[4], value[7], 0,
+ value[2], value[5], value[8], 0,
+ 0, 0, 0, 1);
+
+ value += 9;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
+ }
+
+ delete[] matrix;
+
+ return true;
+}
+
+bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
+{
+ D3DXMATRIX *matrix = new D3DXMATRIX[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12],
+ value[1], value[5], value[9], value[13],
+ value[2], value[6], value[10], value[14],
+ value[3], value[7], value[11], value[15]);
+
+ value += 16;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetMatrixTransposeArray(device, constantPS, matrix, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetMatrixTransposeArray(device, constantVS, matrix, count);
+ }
+
+ delete[] matrix;
+
+ return true;
+}
+
+bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v)
+{
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ D3DXCONSTANT_DESC constantDescription;
+ UINT descriptionCount = 1;
+ HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount);
+ ASSERT(SUCCEEDED(result));
+
+ if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
+ {
+ unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS);
+
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int samplerIndex = firstIndex + i;
+
+ if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
+ {
+ ASSERT(mSamplersPS[samplerIndex].active);
+ mSamplersPS[samplerIndex].logicalTextureUnit = v[i];
+ }
+ }
+ }
+ else
+ {
+ mConstantTablePS->SetIntArray(device, constantPS, v, count);
+ }
+ }
+
+ if (constantVS)
+ {
+ D3DXCONSTANT_DESC constantDescription;
+ UINT descriptionCount = 1;
+ HRESULT result = mConstantTableVS->GetConstantDesc(constantVS, &constantDescription, &descriptionCount);
+ ASSERT(SUCCEEDED(result));
+
+ if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
+ {
+ unsigned int firstIndex = mConstantTableVS->GetSamplerIndex(constantVS);
+
+ for (int i = 0; i < count; i++)
+ {
+ unsigned int samplerIndex = firstIndex + i;
+
+ if (samplerIndex < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF)
+ {
+ ASSERT(mSamplersVS[samplerIndex].active);
+ mSamplersVS[samplerIndex].logicalTextureUnit = v[i];
+ }
+ }
+ }
+ else
+ {
+ mConstantTableVS->SetIntArray(device, constantVS, v, count);
+ }
+ }
+
+ return true;
+}
+
+bool Program::applyUniform2iv(GLint location, GLsizei count, const GLint *v)
+{
+ D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], 0, 0);
+
+ v += 2;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
+ }
+
+ delete[] vector;
+
+ return true;
+}
+
+bool Program::applyUniform3iv(GLint location, GLsizei count, const GLint *v)
+{
+ D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], 0);
+
+ v += 3;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
+ }
+
+ delete[] vector;
+
+ return true;
+}
+
+bool Program::applyUniform4iv(GLint location, GLsizei count, const GLint *v)
+{
+ D3DXVECTOR4 *vector = new D3DXVECTOR4[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ vector[i] = D3DXVECTOR4((float)v[0], (float)v[1], (float)v[2], (float)v[3]);
+
+ v += 4;
+ }
+
+ Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
+
+ D3DXHANDLE constantPS;
+ D3DXHANDLE constantVS;
+ getConstantHandles(targetUniform, &constantPS, &constantVS);
+ IDirect3DDevice9 *device = getDevice();
+
+ if (constantPS)
+ {
+ mConstantTablePS->SetVectorArray(device, constantPS, vector, count);
+ }
+
+ if (constantVS)
+ {
+ mConstantTableVS->SetVectorArray(device, constantVS, vector, count);
+ }
+
+ delete [] vector;
+
+ return true;
+}
+
+
+// append a santized message to the program info log.
+// The D3D compiler includes the current working directory
+// in some of the warning or error messages, so lets remove
+// any occurrances of those that we find in the log.
+void Program::appendToInfoLogSanitized(const char *message)
+{
+ std::string msg(message);
+ CHAR path[MAX_PATH] = "";
+ size_t len;
+
+ len = GetCurrentDirectoryA(MAX_PATH, path);
+ if (len > 0 && len < MAX_PATH)
+ {
+ size_t found;
+ do {
+ found = msg.find(path);
+ if (found != std::string::npos)
+ {
+ // the +1 here is intentional so that we remove
+ // the trailing '\' that occurs after the path
+ msg.erase(found, len+1);
+ }
+ } while (found != std::string::npos);
+ }
+
+ appendToInfoLog("%s\n", msg.c_str());
+}
+
+void Program::appendToInfoLog(const char *format, ...)
+{
+ if (!format)
+ {
+ return;
+ }
+
+ char info[1024];
+
+ va_list vararg;
+ va_start(vararg, format);
+ vsnprintf(info, sizeof(info), format, vararg);
+ va_end(vararg);
+
+ size_t infoLength = strlen(info);
+
+ if (!mInfoLog)
+ {
+ mInfoLog = new char[infoLength + 1];
+ strcpy(mInfoLog, info);
+ }
+ else
+ {
+ size_t logLength = strlen(mInfoLog);
+ char *newLog = new char[logLength + infoLength + 1];
+ strcpy(newLog, mInfoLog);
+ strcpy(newLog + logLength, info);
+
+ delete[] mInfoLog;
+ mInfoLog = newLog;
+ }
+}
+
+void Program::resetInfoLog()
+{
+ if (mInfoLog)
+ {
+ delete [] mInfoLog;
+ mInfoLog = NULL;
+ }
+}
+
+// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction
+void Program::unlink(bool destroy)
+{
+ if (destroy) // Object being destructed
+ {
+ if (mFragmentShader)
+ {
+ mFragmentShader->release();
+ mFragmentShader = NULL;
+ }
+
+ if (mVertexShader)
+ {
+ mVertexShader->release();
+ mVertexShader = NULL;
+ }
+ }
+
+ if (mPixelExecutable)
+ {
+ mPixelExecutable->Release();
+ mPixelExecutable = NULL;
+ }
+
+ if (mVertexExecutable)
+ {
+ mVertexExecutable->Release();
+ mVertexExecutable = NULL;
+ }
+
+ if (mConstantTablePS)
+ {
+ mConstantTablePS->Release();
+ mConstantTablePS = NULL;
+ }
+
+ if (mConstantTableVS)
+ {
+ mConstantTableVS->Release();
+ mConstantTableVS = NULL;
+ }
+
+ for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+ {
+ mLinkedAttribute[index].name.clear();
+ mSemanticIndex[index] = -1;
+ }
+
+ for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
+ {
+ mSamplersPS[index].active = false;
+ }
+
+ for (int index = 0; index < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; index++)
+ {
+ mSamplersVS[index].active = false;
+ }
+
+ while (!mUniforms.empty())
+ {
+ delete mUniforms.back();
+ mUniforms.pop_back();
+ }
+
+ mDxDepthRangeLocation = -1;
+ mDxDepthLocation = -1;
+ mDxViewportLocation = -1;
+ mDxHalfPixelSizeLocation = -1;
+ mDxFrontCCWLocation = -1;
+ mDxPointsOrLinesLocation = -1;
+
+ mUniformIndex.clear();
+
+ mPixelHLSL.clear();
+ mVertexHLSL.clear();
+
+ delete[] mInfoLog;
+ mInfoLog = NULL;
+
+ mLinked = false;
+}
+
+bool Program::isLinked()
+{
+ return mLinked;
+}
+
+bool Program::isValidated() const
+{
+ return mValidated;
+}
+
+void Program::release()
+{
+ mRefCount--;
+
+ if (mRefCount == 0 && mDeleteStatus)
+ {
+ mResourceManager->deleteProgram(mHandle);
+ }
+}
+
+void Program::addRef()
+{
+ mRefCount++;
+}
+
+unsigned int Program::getRefCount() const
+{
+ return mRefCount;
+}
+
+unsigned int Program::getSerial() const
+{
+ return mSerial;
+}
+
+unsigned int Program::issueSerial()
+{
+ return mCurrentSerial++;
+}
+
+int Program::getInfoLogLength() const
+{
+ if (!mInfoLog)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mInfoLog) + 1;
+ }
+}
+
+void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+ int index = 0;
+
+ if (mInfoLog)
+ {
+ while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
+ {
+ infoLog[index] = mInfoLog[index];
+ index++;
+ }
+ }
+
+ if (bufSize)
+ {
+ infoLog[index] = '\0';
+ }
+
+ if (length)
+ {
+ *length = index;
+ }
+}
+
+void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
+{
+ int total = 0;
+
+ if (mVertexShader)
+ {
+ if (total < maxCount)
+ {
+ shaders[total] = mVertexShader->getHandle();
+ }
+
+ total++;
+ }
+
+ if (mFragmentShader)
+ {
+ if (total < maxCount)
+ {
+ shaders[total] = mFragmentShader->getHandle();
+ }
+
+ total++;
+ }
+
+ if (count)
+ {
+ *count = total;
+ }
+}
+
+void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ // Skip over inactive attributes
+ unsigned int activeAttribute = 0;
+ unsigned int attribute;
+ for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
+ {
+ if (mLinkedAttribute[attribute].name.empty())
+ {
+ continue;
+ }
+
+ if (activeAttribute == index)
+ {
+ break;
+ }
+
+ activeAttribute++;
+ }
+
+ if (bufsize > 0)
+ {
+ const char *string = mLinkedAttribute[attribute].name.c_str();
+
+ strncpy(name, string, bufsize);
+ name[bufsize - 1] = '\0';
+
+ if (length)
+ {
+ *length = strlen(name);
+ }
+ }
+
+ *size = 1; // Always a single 'type' instance
+
+ *type = mLinkedAttribute[attribute].type;
+}
+
+GLint Program::getActiveAttributeCount()
+{
+ int count = 0;
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ if (!mLinkedAttribute[attributeIndex].name.empty())
+ {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+GLint Program::getActiveAttributeMaxLength()
+{
+ int maxLength = 0;
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ if (!mLinkedAttribute[attributeIndex].name.empty())
+ {
+ maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
+ }
+ }
+
+ return maxLength;
+}
+
+void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ // Skip over internal uniforms
+ unsigned int activeUniform = 0;
+ unsigned int uniform;
+ for (uniform = 0; uniform < mUniforms.size(); uniform++)
+ {
+ if (mUniforms[uniform]->name.substr(0, 3) == "dx_")
+ {
+ continue;
+ }
+
+ if (activeUniform == index)
+ {
+ break;
+ }
+
+ activeUniform++;
+ }
+
+ ASSERT(uniform < mUniforms.size()); // index must be smaller than getActiveUniformCount()
+
+ if (bufsize > 0)
+ {
+ std::string string = undecorate(mUniforms[uniform]->name);
+
+ if (mUniforms[uniform]->arraySize != 1)
+ {
+ string += "[0]";
+ }
+
+ strncpy(name, string.c_str(), bufsize);
+ name[bufsize - 1] = '\0';
+
+ if (length)
+ {
+ *length = strlen(name);
+ }
+ }
+
+ *size = mUniforms[uniform]->arraySize;
+
+ *type = mUniforms[uniform]->type;
+}
+
+GLint Program::getActiveUniformCount()
+{
+ int count = 0;
+
+ unsigned int numUniforms = mUniforms.size();
+ for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
+ {
+ if (mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
+ {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+GLint Program::getActiveUniformMaxLength()
+{
+ int maxLength = 0;
+
+ unsigned int numUniforms = mUniforms.size();
+ for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
+ {
+ if (!mUniforms[uniformIndex]->name.empty() && mUniforms[uniformIndex]->name.substr(0, 3) != "dx_")
+ {
+ int length = (int)(undecorate(mUniforms[uniformIndex]->name).length() + 1);
+ if (mUniforms[uniformIndex]->arraySize != 1)
+ {
+ length += 3; // Counting in "[0]".
+ }
+ maxLength = std::max(length, maxLength);
+ }
+ }
+
+ return maxLength;
+}
+
+void Program::flagForDeletion()
+{
+ mDeleteStatus = true;
+}
+
+bool Program::isFlaggedForDeletion() const
+{
+ return mDeleteStatus;
+}
+
+void Program::validate()
+{
+ resetInfoLog();
+
+ if (!isLinked())
+ {
+ appendToInfoLog("Program has not been successfully linked.");
+ mValidated = false;
+ }
+ else
+ {
+ applyUniforms();
+ if (!validateSamplers(true))
+ {
+ mValidated = false;
+ }
+ else
+ {
+ mValidated = true;
+ }
+ }
+}
+
+bool Program::validateSamplers(bool logErrors)
+{
+ // if any two active samplers in a program are of different types, but refer to the same
+ // texture image unit, and this is the current program, then ValidateProgram will fail, and
+ // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
+
+ const unsigned int maxCombinedTextureImageUnits = getContext()->getMaximumCombinedTextureImageUnits();
+ TextureType textureUnitType[MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF];
+
+ for (unsigned int i = 0; i < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; ++i)
+ {
+ textureUnitType[i] = TEXTURE_UNKNOWN;
+ }
+
+ for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
+ {
+ if (mSamplersPS[i].active)
+ {
+ unsigned int unit = mSamplersPS[i].logicalTextureUnit;
+
+ if (unit >= maxCombinedTextureImageUnits)
+ {
+ if (logErrors)
+ {
+ appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
+ }
+
+ return false;
+ }
+
+ if (textureUnitType[unit] != TEXTURE_UNKNOWN)
+ {
+ if (mSamplersPS[i].textureType != textureUnitType[unit])
+ {
+ if (logErrors)
+ {
+ appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+ }
+
+ return false;
+ }
+ }
+ else
+ {
+ textureUnitType[unit] = mSamplersPS[i].textureType;
+ }
+ }
+ }
+
+ for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
+ {
+ if (mSamplersVS[i].active)
+ {
+ unsigned int unit = mSamplersVS[i].logicalTextureUnit;
+
+ if (unit >= maxCombinedTextureImageUnits)
+ {
+ if (logErrors)
+ {
+ appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
+ }
+
+ return false;
+ }
+
+ if (textureUnitType[unit] != TEXTURE_UNKNOWN)
+ {
+ if (mSamplersVS[i].textureType != textureUnitType[unit])
+ {
+ if (logErrors)
+ {
+ appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+ }
+
+ return false;
+ }
+ }
+ else
+ {
+ textureUnitType[unit] = mSamplersVS[i].textureType;
+ }
+ }
+ }
+
+ return true;
+}
+
+void Program::getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS)
+{
+ if (!targetUniform->handlesSet)
+ {
+ targetUniform->psHandle = mConstantTablePS->GetConstantByName(0, targetUniform->name.c_str());
+ targetUniform->vsHandle = mConstantTableVS->GetConstantByName(0, targetUniform->name.c_str());
+ targetUniform->handlesSet = true;
+ }
+
+ *constantPS = targetUniform->psHandle;
+ *constantVS = targetUniform->vsHandle;
+}
+
+GLint Program::getDxDepthRangeLocation() const
+{
+ return mDxDepthRangeLocation;
+}
+
+GLint Program::getDxDepthLocation() const
+{
+ return mDxDepthLocation;
+}
+
+GLint Program::getDxViewportLocation() const
+{
+ return mDxViewportLocation;
+}
+
+GLint Program::getDxHalfPixelSizeLocation() const
+{
+ return mDxHalfPixelSizeLocation;
+}
+
+GLint Program::getDxFrontCCWLocation() const
+{
+ return mDxFrontCCWLocation;
+}
+
+GLint Program::getDxPointsOrLinesLocation() const
+{
+ return mDxPointsOrLinesLocation;
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Program.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Program.h
new file mode 100644
index 000000000..8085522eb
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Program.h
@@ -0,0 +1,226 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Program.h: Defines the gl::Program class. Implements GL program objects
+// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
+
+#ifndef LIBGLESV2_PROGRAM_H_
+#define LIBGLESV2_PROGRAM_H_
+
+#include <d3dx9.h>
+#include <d3dcompiler.h>
+#include <string>
+#include <vector>
+#include <set>
+
+#include "libGLESv2/Shader.h"
+#include "libGLESv2/Context.h"
+
+namespace gl
+{
+class ResourceManager;
+class FragmentShader;
+class VertexShader;
+
+// Helper struct representing a single shader uniform
+struct Uniform
+{
+ Uniform(GLenum type, const std::string &name, unsigned int arraySize);
+
+ ~Uniform();
+
+ const GLenum type;
+ const std::string name;
+ const unsigned int arraySize;
+
+ unsigned char *data;
+ bool dirty;
+
+ D3DXHANDLE vsHandle;
+ D3DXHANDLE psHandle;
+ bool handlesSet;
+};
+
+// Struct used for correlating uniforms/elements of uniform arrays to handles
+struct UniformLocation
+{
+ UniformLocation(const std::string &name, unsigned int element, unsigned int index);
+
+ std::string name;
+ unsigned int element;
+ unsigned int index;
+};
+
+class Program
+{
+ public:
+ Program(ResourceManager *manager, GLuint handle);
+
+ ~Program();
+
+ bool attachShader(Shader *shader);
+ bool detachShader(Shader *shader);
+ int getAttachedShadersCount() const;
+
+ IDirect3DPixelShader9 *getPixelShader();
+ IDirect3DVertexShader9 *getVertexShader();
+
+ void bindAttributeLocation(GLuint index, const char *name);
+ GLuint getAttributeLocation(const char *name);
+ int getSemanticIndex(int attributeIndex);
+
+ GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex);
+ TextureType getSamplerTextureType(SamplerType type, unsigned int samplerIndex);
+
+ GLint getUniformLocation(const char *name, bool decorated);
+ bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
+ bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
+ bool setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
+ bool setUniform4fv(GLint location, GLsizei count, const GLfloat *v);
+ bool setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value);
+ bool setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value);
+ bool setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value);
+ bool setUniform1iv(GLint location, GLsizei count, const GLint *v);
+ bool setUniform2iv(GLint location, GLsizei count, const GLint *v);
+ bool setUniform3iv(GLint location, GLsizei count, const GLint *v);
+ bool setUniform4iv(GLint location, GLsizei count, const GLint *v);
+
+ bool getUniformfv(GLint location, GLfloat *params);
+ bool getUniformiv(GLint location, GLint *params);
+
+ GLint getDxDepthRangeLocation() const;
+ GLint getDxDepthLocation() const;
+ GLint getDxViewportLocation() const;
+ GLint getDxHalfPixelSizeLocation() const;
+ GLint getDxFrontCCWLocation() const;
+ GLint getDxPointsOrLinesLocation() const;
+
+ void dirtyAllUniforms();
+ void applyUniforms();
+
+ void link();
+ bool isLinked();
+ int getInfoLogLength() const;
+ void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+ void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
+
+ void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+ GLint getActiveAttributeCount();
+ GLint getActiveAttributeMaxLength();
+
+ void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
+ GLint getActiveUniformCount();
+ GLint getActiveUniformMaxLength();
+
+ void addRef();
+ void release();
+ unsigned int getRefCount() const;
+ void flagForDeletion();
+ bool isFlaggedForDeletion() const;
+
+ void validate();
+ bool validateSamplers(bool logErrors);
+ bool isValidated() const;
+
+ unsigned int getSerial() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Program);
+
+ ID3D10Blob *compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable);
+ void unlink(bool destroy = false);
+
+ int packVaryings(const Varying *packing[][4]);
+ bool linkVaryings();
+
+ bool linkAttributes();
+ int getAttributeBinding(const std::string &name);
+
+ bool linkUniforms(ID3DXConstantTable *constantTable);
+ bool defineUniform(const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name = "");
+ bool defineUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name);
+ Uniform *createUniform(const D3DXCONSTANT_DESC &constantDescription, std::string &name);
+ bool applyUniform1bv(GLint location, GLsizei count, const GLboolean *v);
+ bool applyUniform2bv(GLint location, GLsizei count, const GLboolean *v);
+ bool applyUniform3bv(GLint location, GLsizei count, const GLboolean *v);
+ bool applyUniform4bv(GLint location, GLsizei count, const GLboolean *v);
+ bool applyUniform1fv(GLint location, GLsizei count, const GLfloat *v);
+ bool applyUniform2fv(GLint location, GLsizei count, const GLfloat *v);
+ bool applyUniform3fv(GLint location, GLsizei count, const GLfloat *v);
+ bool applyUniform4fv(GLint location, GLsizei count, const GLfloat *v);
+ bool applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value);
+ bool applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value);
+ bool applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value);
+ bool applyUniform1iv(GLint location, GLsizei count, const GLint *v);
+ bool applyUniform2iv(GLint location, GLsizei count, const GLint *v);
+ bool applyUniform3iv(GLint location, GLsizei count, const GLint *v);
+ bool applyUniform4iv(GLint location, GLsizei count, const GLint *v);
+
+ void getConstantHandles(Uniform *targetUniform, D3DXHANDLE *constantPS, D3DXHANDLE *constantVS);
+
+ void appendToInfoLogSanitized(const char *message);
+ void appendToInfoLog(const char *info, ...);
+ void resetInfoLog();
+
+ static std::string decorate(const std::string &string); // Prepend an underscore
+ static std::string undecorate(const std::string &string); // Remove leading underscore
+
+ static unsigned int issueSerial();
+
+ FragmentShader *mFragmentShader;
+ VertexShader *mVertexShader;
+
+ std::string mPixelHLSL;
+ std::string mVertexHLSL;
+
+ IDirect3DPixelShader9 *mPixelExecutable;
+ IDirect3DVertexShader9 *mVertexExecutable;
+ ID3DXConstantTable *mConstantTablePS;
+ ID3DXConstantTable *mConstantTableVS;
+
+ std::set<std::string> mAttributeBinding[MAX_VERTEX_ATTRIBS];
+ Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS];
+ int mSemanticIndex[MAX_VERTEX_ATTRIBS];
+
+ struct Sampler
+ {
+ bool active;
+ GLint logicalTextureUnit;
+ TextureType textureType;
+ };
+
+ Sampler mSamplersPS[MAX_TEXTURE_IMAGE_UNITS];
+ Sampler mSamplersVS[MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF];
+
+ typedef std::vector<Uniform*> UniformArray;
+ UniformArray mUniforms;
+ typedef std::vector<UniformLocation> UniformIndex;
+ UniformIndex mUniformIndex;
+
+ GLint mDxDepthRangeLocation;
+ GLint mDxDepthLocation;
+ GLint mDxViewportLocation;
+ GLint mDxHalfPixelSizeLocation;
+ GLint mDxFrontCCWLocation;
+ GLint mDxPointsOrLinesLocation;
+
+ bool mLinked;
+ bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use
+ char *mInfoLog;
+ bool mValidated;
+
+ unsigned int mRefCount;
+
+ const unsigned int mSerial;
+
+ static unsigned int mCurrentSerial;
+
+ ResourceManager *mResourceManager;
+ const GLuint mHandle;
+};
+}
+
+#endif // LIBGLESV2_PROGRAM_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/RefCountObject.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/RefCountObject.cpp
new file mode 100644
index 000000000..2de1e718d
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/RefCountObject.cpp
@@ -0,0 +1,52 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RefCountObject.cpp: Defines the gl::RefCountObject base class that provides
+// lifecycle support for GL objects using the traditional BindObject scheme, but
+// that need to be reference counted for correct cross-context deletion.
+// (Concretely, textures, buffers and renderbuffers.)
+
+#include "RefCountObject.h"
+
+namespace gl
+{
+
+RefCountObject::RefCountObject(GLuint id)
+{
+ mId = id;
+ mRefCount = 0;
+}
+
+RefCountObject::~RefCountObject()
+{
+ ASSERT(mRefCount == 0);
+}
+
+void RefCountObject::addRef() const
+{
+ mRefCount++;
+}
+
+void RefCountObject::release() const
+{
+ ASSERT(mRefCount > 0);
+
+ if (--mRefCount == 0)
+ {
+ delete this;
+ }
+}
+
+void RefCountObjectBindingPointer::set(RefCountObject *newObject)
+{
+ // addRef first in case newObject == mObject and this is the last reference to it.
+ if (newObject != NULL) newObject->addRef();
+ if (mObject != NULL) mObject->release();
+
+ mObject = newObject;
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/RefCountObject.h b/Source/ThirdParty/ANGLE/src/libGLESv2/RefCountObject.h
new file mode 100644
index 000000000..a1493505f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/RefCountObject.h
@@ -0,0 +1,70 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// RefCountObject.h: Defines the gl::RefCountObject base class that provides
+// lifecycle support for GL objects using the traditional BindObject scheme, but
+// that need to be reference counted for correct cross-context deletion.
+// (Concretely, textures, buffers and renderbuffers.)
+
+#ifndef LIBGLESV2_REFCOUNTOBJECT_H_
+#define LIBGLESV2_REFCOUNTOBJECT_H_
+
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "common/debug.h"
+
+namespace gl
+{
+
+class RefCountObject
+{
+ public:
+ explicit RefCountObject(GLuint id);
+ virtual ~RefCountObject();
+
+ virtual void addRef() const;
+ virtual void release() const;
+
+ GLuint id() const { return mId; }
+
+ private:
+ GLuint mId;
+
+ mutable std::size_t mRefCount;
+};
+
+class RefCountObjectBindingPointer
+{
+ protected:
+ RefCountObjectBindingPointer() : mObject(NULL) { }
+ ~RefCountObjectBindingPointer() { ASSERT(mObject == NULL); } // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up.
+
+ void set(RefCountObject *newObject);
+ RefCountObject *get() const { return mObject; }
+
+ public:
+ GLuint id() const { return (mObject != NULL) ? mObject->id() : 0; }
+ bool operator ! () const { return (get() == NULL); }
+
+ private:
+ RefCountObject *mObject;
+};
+
+template <class ObjectType>
+class BindingPointer : public RefCountObjectBindingPointer
+{
+ public:
+ void set(ObjectType *newObject) { RefCountObjectBindingPointer::set(newObject); }
+ ObjectType *get() const { return static_cast<ObjectType*>(RefCountObjectBindingPointer::get()); }
+ ObjectType *operator -> () const { return get(); }
+};
+
+}
+
+#endif // LIBGLESV2_REFCOUNTOBJECT_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.cpp
new file mode 100644
index 000000000..ace8d7b90
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.cpp
@@ -0,0 +1,512 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderbuffer.cpp: the gl::Renderbuffer class and its derived classes
+// Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108.
+
+#include "libGLESv2/Renderbuffer.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/Texture.h"
+#include "libGLESv2/utilities.h"
+
+namespace gl
+{
+unsigned int RenderbufferStorage::mCurrentSerial = 1;
+
+Renderbuffer::Renderbuffer(GLuint id, RenderbufferStorage *storage) : RefCountObject(id)
+{
+ ASSERT(storage != NULL);
+ mStorage = storage;
+}
+
+Renderbuffer::~Renderbuffer()
+{
+ delete mStorage;
+}
+
+bool Renderbuffer::isColorbuffer() const
+{
+ return mStorage->isColorbuffer();
+}
+
+bool Renderbuffer::isDepthbuffer() const
+{
+ return mStorage->isDepthbuffer();
+}
+
+bool Renderbuffer::isStencilbuffer() const
+{
+ return mStorage->isStencilbuffer();
+}
+
+IDirect3DSurface9 *Renderbuffer::getRenderTarget()
+{
+ return mStorage->getRenderTarget();
+}
+
+IDirect3DSurface9 *Renderbuffer::getDepthStencil()
+{
+ return mStorage->getDepthStencil();
+}
+
+GLsizei Renderbuffer::getWidth() const
+{
+ return mStorage->getWidth();
+}
+
+GLsizei Renderbuffer::getHeight() const
+{
+ return mStorage->getHeight();
+}
+
+GLenum Renderbuffer::getInternalFormat() const
+{
+ return mStorage->getInternalFormat();
+}
+
+GLuint Renderbuffer::getRedSize() const
+{
+ return mStorage->getRedSize();
+}
+
+GLuint Renderbuffer::getGreenSize() const
+{
+ return mStorage->getGreenSize();
+}
+
+GLuint Renderbuffer::getBlueSize() const
+{
+ return mStorage->getBlueSize();
+}
+
+GLuint Renderbuffer::getAlphaSize() const
+{
+ return mStorage->getAlphaSize();
+}
+
+GLuint Renderbuffer::getDepthSize() const
+{
+ return mStorage->getDepthSize();
+}
+
+GLuint Renderbuffer::getStencilSize() const
+{
+ return mStorage->getStencilSize();
+}
+
+GLsizei Renderbuffer::getSamples() const
+{
+ return mStorage->getSamples();
+}
+
+unsigned int Renderbuffer::getSerial() const
+{
+ return mStorage->getSerial();
+}
+
+void Renderbuffer::setStorage(RenderbufferStorage *newStorage)
+{
+ ASSERT(newStorage != NULL);
+
+ delete mStorage;
+ mStorage = newStorage;
+}
+
+RenderbufferStorage::RenderbufferStorage() : mSerial(issueSerial())
+{
+ mWidth = 0;
+ mHeight = 0;
+ mInternalFormat = GL_RGBA4;
+ mD3DFormat = D3DFMT_A8R8G8B8;
+ mSamples = 0;
+}
+
+RenderbufferStorage::~RenderbufferStorage()
+{
+}
+
+bool RenderbufferStorage::isColorbuffer() const
+{
+ return false;
+}
+
+bool RenderbufferStorage::isDepthbuffer() const
+{
+ return false;
+}
+
+bool RenderbufferStorage::isStencilbuffer() const
+{
+ return false;
+}
+
+IDirect3DSurface9 *RenderbufferStorage::getRenderTarget()
+{
+ return NULL;
+}
+
+IDirect3DSurface9 *RenderbufferStorage::getDepthStencil()
+{
+ return NULL;
+}
+
+GLsizei RenderbufferStorage::getWidth() const
+{
+ return mWidth;
+}
+
+GLsizei RenderbufferStorage::getHeight() const
+{
+ return mHeight;
+}
+
+GLenum RenderbufferStorage::getInternalFormat() const
+{
+ return mInternalFormat;
+}
+
+GLuint RenderbufferStorage::getRedSize() const
+{
+ return dx2es::GetRedSize(getD3DFormat());
+}
+
+GLuint RenderbufferStorage::getGreenSize() const
+{
+ return dx2es::GetGreenSize(getD3DFormat());
+}
+
+GLuint RenderbufferStorage::getBlueSize() const
+{
+ return dx2es::GetBlueSize(getD3DFormat());
+}
+
+GLuint RenderbufferStorage::getAlphaSize() const
+{
+ return dx2es::GetAlphaSize(getD3DFormat());
+}
+
+GLuint RenderbufferStorage::getDepthSize() const
+{
+ return dx2es::GetDepthSize(getD3DFormat());
+}
+
+GLuint RenderbufferStorage::getStencilSize() const
+{
+ return dx2es::GetStencilSize(getD3DFormat());
+}
+
+GLsizei RenderbufferStorage::getSamples() const
+{
+ return mSamples;
+}
+
+D3DFORMAT RenderbufferStorage::getD3DFormat() const
+{
+ return mD3DFormat;
+}
+
+unsigned int RenderbufferStorage::getSerial() const
+{
+ return mSerial;
+}
+
+unsigned int RenderbufferStorage::issueSerial()
+{
+ return mCurrentSerial++;
+}
+
+Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget), mTexture(NULL)
+{
+ if (renderTarget)
+ {
+ renderTarget->AddRef();
+
+ D3DSURFACE_DESC description;
+ renderTarget->GetDesc(&description);
+
+ mWidth = description.Width;
+ mHeight = description.Height;
+ mInternalFormat = dx2es::ConvertBackBufferFormat(description.Format);
+ mD3DFormat = description.Format;
+ mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType);
+ }
+}
+
+Colorbuffer::Colorbuffer(Texture *texture, GLenum target) : mRenderTarget(NULL), mTexture(texture), mTarget(target)
+{
+ if (texture)
+ {
+ mWidth = texture->getWidth();
+ mHeight = texture->getHeight();
+ mInternalFormat = texture->getInternalFormat();
+ mD3DFormat = texture->getD3DFormat();
+ mSamples = 0;
+
+ mRenderTarget = texture->getRenderTarget(target);
+ }
+}
+
+Colorbuffer::Colorbuffer(int width, int height, GLenum format, GLsizei samples) : mRenderTarget(NULL), mTexture(NULL)
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ D3DFORMAT requestedFormat = es2dx::ConvertRenderbufferFormat(format);
+ int supportedSamples = getContext()->getNearestSupportedSamples(requestedFormat, samples);
+
+ if (supportedSamples == -1)
+ {
+ error(GL_OUT_OF_MEMORY);
+
+ return;
+ }
+
+ if (width > 0 && height > 0)
+ {
+ HRESULT result = device->CreateRenderTarget(width, height, requestedFormat,
+ es2dx::GetMultisampleTypeFromSamples(supportedSamples), 0, FALSE, &mRenderTarget, NULL);
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ error(GL_OUT_OF_MEMORY);
+
+ return;
+ }
+
+ ASSERT(SUCCEEDED(result));
+ }
+
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = format;
+ mD3DFormat = requestedFormat;
+ mSamples = supportedSamples;
+}
+
+Colorbuffer::~Colorbuffer()
+{
+ if (mRenderTarget)
+ {
+ mRenderTarget->Release();
+ }
+}
+
+GLsizei Colorbuffer::getWidth() const
+{
+ if (mTexture)
+ {
+ return mTexture->getWidth();
+ }
+
+ return mWidth;
+}
+
+GLsizei Colorbuffer::getHeight() const
+{
+ if (mTexture)
+ {
+ return mTexture->getHeight();
+ }
+
+ return mHeight;
+}
+
+GLenum Colorbuffer::getInternalFormat() const
+{
+ if (mTexture)
+ {
+ return mTexture->getInternalFormat();
+ }
+
+ return mInternalFormat;
+}
+
+GLenum Colorbuffer::getType() const
+{
+ if (mTexture)
+ {
+ return mTexture->getType();
+ }
+
+ return GL_UNSIGNED_BYTE;
+}
+
+D3DFORMAT Colorbuffer::getD3DFormat() const
+{
+ if (mTexture)
+ {
+ return mTexture->getD3DFormat();
+ }
+
+ return mD3DFormat;
+}
+
+bool Colorbuffer::isColorbuffer() const
+{
+ return true;
+}
+
+IDirect3DSurface9 *Colorbuffer::getRenderTarget()
+{
+ if (mTexture)
+ {
+ if (mRenderTarget)
+ {
+ mRenderTarget->Release();
+ }
+
+ mRenderTarget = mTexture->getRenderTarget(mTarget);
+ }
+
+ return mRenderTarget;
+}
+
+DepthStencilbuffer::DepthStencilbuffer(IDirect3DSurface9 *depthStencil) : mDepthStencil(depthStencil)
+{
+ if (depthStencil)
+ {
+ depthStencil->AddRef();
+
+ D3DSURFACE_DESC description;
+ depthStencil->GetDesc(&description);
+
+ mWidth = description.Width;
+ mHeight = description.Height;
+ mInternalFormat = dx2es::ConvertDepthStencilFormat(description.Format);
+ mSamples = dx2es::GetSamplesFromMultisampleType(description.MultiSampleType);
+ mD3DFormat = description.Format;
+ }
+}
+
+DepthStencilbuffer::DepthStencilbuffer(int width, int height, GLsizei samples)
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ mDepthStencil = NULL;
+
+ int supportedSamples = getContext()->getNearestSupportedSamples(D3DFMT_D24S8, samples);
+
+ if (supportedSamples == -1)
+ {
+ error(GL_OUT_OF_MEMORY);
+
+ return;
+ }
+
+ if (width > 0 && height > 0)
+ {
+ HRESULT result = device->CreateDepthStencilSurface(width, height, D3DFMT_D24S8, es2dx::GetMultisampleTypeFromSamples(supportedSamples),
+ 0, FALSE, &mDepthStencil, 0);
+
+ if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ {
+ error(GL_OUT_OF_MEMORY);
+
+ return;
+ }
+
+ ASSERT(SUCCEEDED(result));
+ }
+
+ mWidth = width;
+ mHeight = height;
+ mInternalFormat = GL_DEPTH24_STENCIL8_OES;
+ mD3DFormat = D3DFMT_D24S8;
+ mSamples = supportedSamples;
+}
+
+DepthStencilbuffer::~DepthStencilbuffer()
+{
+ if (mDepthStencil)
+ {
+ mDepthStencil->Release();
+ }
+}
+
+bool DepthStencilbuffer::isDepthbuffer() const
+{
+ return true;
+}
+
+bool DepthStencilbuffer::isStencilbuffer() const
+{
+ return true;
+}
+
+IDirect3DSurface9 *DepthStencilbuffer::getDepthStencil()
+{
+ return mDepthStencil;
+}
+
+Depthbuffer::Depthbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil)
+{
+ if (depthStencil)
+ {
+ mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
+ }
+}
+
+Depthbuffer::Depthbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples)
+{
+ if (getDepthStencil())
+ {
+ mInternalFormat = GL_DEPTH_COMPONENT16; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
+ }
+}
+
+Depthbuffer::~Depthbuffer()
+{
+}
+
+bool Depthbuffer::isDepthbuffer() const
+{
+ return true;
+}
+
+bool Depthbuffer::isStencilbuffer() const
+{
+ return false;
+}
+
+Stencilbuffer::Stencilbuffer(IDirect3DSurface9 *depthStencil) : DepthStencilbuffer(depthStencil)
+{
+ if (depthStencil)
+ {
+ mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
+ }
+}
+
+Stencilbuffer::Stencilbuffer(int width, int height, GLsizei samples) : DepthStencilbuffer(width, height, samples)
+{
+ if (getDepthStencil())
+ {
+ mInternalFormat = GL_STENCIL_INDEX8; // If the renderbuffer parameters are queried, the calling function
+ // will expect one of the valid renderbuffer formats for use in
+ // glRenderbufferStorage
+ }
+}
+
+Stencilbuffer::~Stencilbuffer()
+{
+}
+
+bool Stencilbuffer::isDepthbuffer() const
+{
+ return false;
+}
+
+bool Stencilbuffer::isStencilbuffer() const
+{
+ return true;
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.h
new file mode 100644
index 000000000..5cf829c70
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Renderbuffer.h
@@ -0,0 +1,192 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Renderbuffer.h: Defines the wrapper class gl::Renderbuffer, as well as the
+// class hierarchy used to store its contents: RenderbufferStorage, Colorbuffer,
+// DepthStencilbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer
+// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108.
+
+#ifndef LIBGLESV2_RENDERBUFFER_H_
+#define LIBGLESV2_RENDERBUFFER_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <d3d9.h>
+
+#include "common/angleutils.h"
+#include "libGLESv2/RefCountObject.h"
+
+namespace gl
+{
+class Texture;
+
+// A class derived from RenderbufferStorage is created whenever glRenderbufferStorage
+// is called. The specific concrete type depends on whether the internal format is
+// colour depth, stencil or packed depth/stencil.
+class RenderbufferStorage
+{
+ public:
+ RenderbufferStorage();
+
+ virtual ~RenderbufferStorage() = 0;
+
+ virtual bool isColorbuffer() const;
+ virtual bool isDepthbuffer() const;
+ virtual bool isStencilbuffer() const;
+
+ virtual IDirect3DSurface9 *getRenderTarget();
+ virtual IDirect3DSurface9 *getDepthStencil();
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
+ GLuint getRedSize() const;
+ GLuint getGreenSize() const;
+ GLuint getBlueSize() const;
+ GLuint getAlphaSize() const;
+ GLuint getDepthSize() const;
+ GLuint getStencilSize() const;
+ virtual GLsizei getSamples() const;
+
+ virtual D3DFORMAT getD3DFormat() const;
+
+ unsigned int getSerial() const;
+
+ protected:
+ GLsizei mWidth;
+ GLsizei mHeight;
+ GLenum mInternalFormat;
+ D3DFORMAT mD3DFormat;
+ GLsizei mSamples;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RenderbufferStorage);
+
+ static unsigned int issueSerial();
+
+ const unsigned int mSerial;
+
+ static unsigned int mCurrentSerial;
+};
+
+// Renderbuffer implements the GL renderbuffer object.
+// It's only a proxy for a RenderbufferStorage instance; the internal object
+// can change whenever glRenderbufferStorage is called.
+class Renderbuffer : public RefCountObject
+{
+ public:
+ Renderbuffer(GLuint id, RenderbufferStorage *storage);
+
+ ~Renderbuffer();
+
+ bool isColorbuffer() const;
+ bool isDepthbuffer() const;
+ bool isStencilbuffer() const;
+
+ IDirect3DSurface9 *getRenderTarget();
+ IDirect3DSurface9 *getDepthStencil();
+
+ GLsizei getWidth() const;
+ GLsizei getHeight() const;
+ GLenum getInternalFormat() const;
+ D3DFORMAT getD3DFormat() const;
+ GLuint getRedSize() const;
+ GLuint getGreenSize() const;
+ GLuint getBlueSize() const;
+ GLuint getAlphaSize() const;
+ GLuint getDepthSize() const;
+ GLuint getStencilSize() const;
+ GLsizei getSamples() const;
+
+ unsigned int getSerial() const;
+
+ void setStorage(RenderbufferStorage *newStorage);
+ RenderbufferStorage *getStorage() { return mStorage; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Renderbuffer);
+
+ RenderbufferStorage *mStorage;
+};
+
+class Colorbuffer : public RenderbufferStorage
+{
+ public:
+ explicit Colorbuffer(IDirect3DSurface9 *renderTarget);
+ Colorbuffer(Texture *texture, GLenum target);
+ Colorbuffer(GLsizei width, GLsizei height, GLenum format, GLsizei samples);
+
+ virtual ~Colorbuffer();
+
+ virtual bool isColorbuffer() const;
+
+ virtual IDirect3DSurface9 *getRenderTarget();
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
+ virtual GLenum getType() const;
+
+ virtual D3DFORMAT getD3DFormat() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Colorbuffer);
+
+ IDirect3DSurface9 *mRenderTarget;
+ Texture *mTexture;
+ GLenum mTarget;
+};
+
+class DepthStencilbuffer : public RenderbufferStorage
+{
+ public:
+ explicit DepthStencilbuffer(IDirect3DSurface9 *depthStencil);
+ DepthStencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
+
+ ~DepthStencilbuffer();
+
+ virtual bool isDepthbuffer() const;
+ virtual bool isStencilbuffer() const;
+
+ virtual IDirect3DSurface9 *getDepthStencil();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DepthStencilbuffer);
+ IDirect3DSurface9 *mDepthStencil;
+};
+
+class Depthbuffer : public DepthStencilbuffer
+{
+ public:
+ explicit Depthbuffer(IDirect3DSurface9 *depthStencil);
+ Depthbuffer(GLsizei width, GLsizei height, GLsizei samples);
+
+ virtual ~Depthbuffer();
+
+ virtual bool isDepthbuffer() const;
+ virtual bool isStencilbuffer() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Depthbuffer);
+};
+
+class Stencilbuffer : public DepthStencilbuffer
+{
+ public:
+ explicit Stencilbuffer(IDirect3DSurface9 *depthStencil);
+ Stencilbuffer(GLsizei width, GLsizei height, GLsizei samples);
+
+ virtual ~Stencilbuffer();
+
+ virtual bool isDepthbuffer() const;
+ virtual bool isStencilbuffer() const;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Stencilbuffer);
+};
+}
+
+#endif // LIBGLESV2_RENDERBUFFER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.cpp
new file mode 100644
index 000000000..ae26352e0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.cpp
@@ -0,0 +1,320 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ResourceManager.cpp: Implements the gl::ResourceManager class, which tracks and
+// retrieves objects which may be shared by multiple Contexts.
+
+#include "libGLESv2/ResourceManager.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/RenderBuffer.h"
+#include "libGLESv2/Shader.h"
+#include "libGLESv2/Texture.h"
+
+namespace gl
+{
+ResourceManager::ResourceManager()
+{
+ mRefCount = 1;
+}
+
+ResourceManager::~ResourceManager()
+{
+ while (!mBufferMap.empty())
+ {
+ deleteBuffer(mBufferMap.begin()->first);
+ }
+
+ while (!mProgramMap.empty())
+ {
+ deleteProgram(mProgramMap.begin()->first);
+ }
+
+ while (!mShaderMap.empty())
+ {
+ deleteShader(mShaderMap.begin()->first);
+ }
+
+ while (!mRenderbufferMap.empty())
+ {
+ deleteRenderbuffer(mRenderbufferMap.begin()->first);
+ }
+
+ while (!mTextureMap.empty())
+ {
+ deleteTexture(mTextureMap.begin()->first);
+ }
+}
+
+void ResourceManager::addRef()
+{
+ mRefCount++;
+}
+
+void ResourceManager::release()
+{
+ if (--mRefCount == 0)
+ {
+ delete this;
+ }
+}
+
+// Returns an unused buffer name
+GLuint ResourceManager::createBuffer()
+{
+ GLuint handle = mBufferHandleAllocator.allocate();
+
+ mBufferMap[handle] = NULL;
+
+ return handle;
+}
+
+// Returns an unused shader/program name
+GLuint ResourceManager::createShader(GLenum type)
+{
+ GLuint handle = mProgramShaderHandleAllocator.allocate();
+
+ if (type == GL_VERTEX_SHADER)
+ {
+ mShaderMap[handle] = new VertexShader(this, handle);
+ }
+ else if (type == GL_FRAGMENT_SHADER)
+ {
+ mShaderMap[handle] = new FragmentShader(this, handle);
+ }
+ else UNREACHABLE();
+
+ return handle;
+}
+
+// Returns an unused program/shader name
+GLuint ResourceManager::createProgram()
+{
+ GLuint handle = mProgramShaderHandleAllocator.allocate();
+
+ mProgramMap[handle] = new Program(this, handle);
+
+ return handle;
+}
+
+// Returns an unused texture name
+GLuint ResourceManager::createTexture()
+{
+ GLuint handle = mTextureHandleAllocator.allocate();
+
+ mTextureMap[handle] = NULL;
+
+ return handle;
+}
+
+// Returns an unused renderbuffer name
+GLuint ResourceManager::createRenderbuffer()
+{
+ GLuint handle = mRenderbufferHandleAllocator.allocate();
+
+ mRenderbufferMap[handle] = NULL;
+
+ return handle;
+}
+
+void ResourceManager::deleteBuffer(GLuint buffer)
+{
+ BufferMap::iterator bufferObject = mBufferMap.find(buffer);
+
+ if (bufferObject != mBufferMap.end())
+ {
+ mBufferHandleAllocator.release(bufferObject->first);
+ if (bufferObject->second) bufferObject->second->release();
+ mBufferMap.erase(bufferObject);
+ }
+}
+
+void ResourceManager::deleteShader(GLuint shader)
+{
+ ShaderMap::iterator shaderObject = mShaderMap.find(shader);
+
+ if (shaderObject != mShaderMap.end())
+ {
+ if (shaderObject->second->getRefCount() == 0)
+ {
+ mProgramShaderHandleAllocator.release(shaderObject->first);
+ delete shaderObject->second;
+ mShaderMap.erase(shaderObject);
+ }
+ else
+ {
+ shaderObject->second->flagForDeletion();
+ }
+ }
+}
+
+void ResourceManager::deleteProgram(GLuint program)
+{
+ ProgramMap::iterator programObject = mProgramMap.find(program);
+
+ if (programObject != mProgramMap.end())
+ {
+ if (programObject->second->getRefCount() == 0)
+ {
+ mProgramShaderHandleAllocator.release(programObject->first);
+ delete programObject->second;
+ mProgramMap.erase(programObject);
+ }
+ else
+ {
+ programObject->second->flagForDeletion();
+ }
+ }
+}
+
+void ResourceManager::deleteTexture(GLuint texture)
+{
+ TextureMap::iterator textureObject = mTextureMap.find(texture);
+
+ if (textureObject != mTextureMap.end())
+ {
+ mTextureHandleAllocator.release(textureObject->first);
+ if (textureObject->second) textureObject->second->release();
+ mTextureMap.erase(textureObject);
+ }
+}
+
+void ResourceManager::deleteRenderbuffer(GLuint renderbuffer)
+{
+ RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer);
+
+ if (renderbufferObject != mRenderbufferMap.end())
+ {
+ mRenderbufferHandleAllocator.release(renderbufferObject->first);
+ if (renderbufferObject->second) renderbufferObject->second->release();
+ mRenderbufferMap.erase(renderbufferObject);
+ }
+}
+
+Buffer *ResourceManager::getBuffer(unsigned int handle)
+{
+ BufferMap::iterator buffer = mBufferMap.find(handle);
+
+ if (buffer == mBufferMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return buffer->second;
+ }
+}
+
+Shader *ResourceManager::getShader(unsigned int handle)
+{
+ ShaderMap::iterator shader = mShaderMap.find(handle);
+
+ if (shader == mShaderMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return shader->second;
+ }
+}
+
+Texture *ResourceManager::getTexture(unsigned int handle)
+{
+ if (handle == 0) return NULL;
+
+ TextureMap::iterator texture = mTextureMap.find(handle);
+
+ if (texture == mTextureMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return texture->second;
+ }
+}
+
+Program *ResourceManager::getProgram(unsigned int handle)
+{
+ ProgramMap::iterator program = mProgramMap.find(handle);
+
+ if (program == mProgramMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return program->second;
+ }
+}
+
+Renderbuffer *ResourceManager::getRenderbuffer(unsigned int handle)
+{
+ RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle);
+
+ if (renderbuffer == mRenderbufferMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ return renderbuffer->second;
+ }
+}
+
+void ResourceManager::setRenderbuffer(GLuint handle, Renderbuffer *buffer)
+{
+ mRenderbufferMap[handle] = buffer;
+}
+
+void ResourceManager::checkBufferAllocation(unsigned int buffer)
+{
+ if (buffer != 0 && !getBuffer(buffer))
+ {
+ Buffer *bufferObject = new Buffer(buffer);
+ mBufferMap[buffer] = bufferObject;
+ bufferObject->addRef();
+ }
+}
+
+void ResourceManager::checkTextureAllocation(GLuint texture, TextureType type)
+{
+ if (!getTexture(texture) && texture != 0)
+ {
+ Texture *textureObject;
+
+ if (type == TEXTURE_2D)
+ {
+ textureObject = new Texture2D(texture);
+ }
+ else if (type == TEXTURE_CUBE)
+ {
+ textureObject = new TextureCubeMap(texture);
+ }
+ else
+ {
+ UNREACHABLE();
+ return;
+ }
+
+ mTextureMap[texture] = textureObject;
+ textureObject->addRef();
+ }
+}
+
+void ResourceManager::checkRenderbufferAllocation(GLuint renderbuffer)
+{
+ if (renderbuffer != 0 && !getRenderbuffer(renderbuffer))
+ {
+ Renderbuffer *renderbufferObject = new Renderbuffer(renderbuffer, new Colorbuffer(0, 0, GL_RGBA4, 0));
+ mRenderbufferMap[renderbuffer] = renderbufferObject;
+ renderbufferObject->addRef();
+ }
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.h b/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.h
new file mode 100644
index 000000000..5185fc9db
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/ResourceManager.h
@@ -0,0 +1,104 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ResourceManager.h : Defines the ResourceManager class, which tracks objects
+// shared by multiple GL contexts.
+
+#ifndef LIBGLESV2_RESOURCEMANAGER_H_
+#define LIBGLESV2_RESOURCEMANAGER_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include <hash_map>
+
+#include "common/angleutils.h"
+#include "libGLESv2/HandleAllocator.h"
+
+namespace gl
+{
+class Buffer;
+class Shader;
+class Program;
+class Texture;
+class Renderbuffer;
+
+enum TextureType
+{
+ TEXTURE_2D,
+ TEXTURE_CUBE,
+
+ TEXTURE_TYPE_COUNT,
+ TEXTURE_UNKNOWN
+};
+
+enum SamplerType
+{
+ SAMPLER_PIXEL,
+ SAMPLER_VERTEX
+};
+
+class ResourceManager
+{
+ public:
+ ResourceManager();
+ ~ResourceManager();
+
+ void addRef();
+ void release();
+
+ GLuint createBuffer();
+ GLuint createShader(GLenum type);
+ GLuint createProgram();
+ GLuint createTexture();
+ GLuint createRenderbuffer();
+
+ void deleteBuffer(GLuint buffer);
+ void deleteShader(GLuint shader);
+ void deleteProgram(GLuint program);
+ void deleteTexture(GLuint texture);
+ void deleteRenderbuffer(GLuint renderbuffer);
+
+ Buffer *getBuffer(GLuint handle);
+ Shader *getShader(GLuint handle);
+ Program *getProgram(GLuint handle);
+ Texture *getTexture(GLuint handle);
+ Renderbuffer *getRenderbuffer(GLuint handle);
+
+ void setRenderbuffer(GLuint handle, Renderbuffer *renderbuffer);
+
+ void checkBufferAllocation(unsigned int buffer);
+ void checkTextureAllocation(GLuint texture, TextureType type);
+ void checkRenderbufferAllocation(GLuint renderbuffer);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ResourceManager);
+
+ std::size_t mRefCount;
+
+ typedef stdext::hash_map<GLuint, Buffer*> BufferMap;
+ BufferMap mBufferMap;
+ HandleAllocator mBufferHandleAllocator;
+
+ typedef stdext::hash_map<GLuint, Shader*> ShaderMap;
+ ShaderMap mShaderMap;
+
+ typedef stdext::hash_map<GLuint, Program*> ProgramMap;
+ ProgramMap mProgramMap;
+ HandleAllocator mProgramShaderHandleAllocator;
+
+ typedef stdext::hash_map<GLuint, Texture*> TextureMap;
+ TextureMap mTextureMap;
+ HandleAllocator mTextureHandleAllocator;
+
+ typedef stdext::hash_map<GLuint, Renderbuffer*> RenderbufferMap;
+ RenderbufferMap mRenderbufferMap;
+ HandleAllocator mRenderbufferHandleAllocator;
+};
+
+}
+
+#endif // LIBGLESV2_RESOURCEMANAGER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.cpp
new file mode 100644
index 000000000..f66b2c52a
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.cpp
@@ -0,0 +1,528 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Shader.cpp: Implements the gl::Shader class and its derived classes
+// VertexShader and FragmentShader. Implements GL shader objects and related
+// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
+
+#include "libGLESv2/Shader.h"
+
+#include <string>
+
+#include "GLSLANG/Shaderlang.h"
+#include "libGLESv2/main.h"
+#include "libGLESv2/utilities.h"
+
+namespace gl
+{
+void *Shader::mFragmentCompiler = NULL;
+void *Shader::mVertexCompiler = NULL;
+
+Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mResourceManager(manager)
+{
+ mSource = NULL;
+ mHlsl = NULL;
+ mInfoLog = NULL;
+
+ // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler)
+ if (!mFragmentCompiler)
+ {
+ int result = ShInitialize();
+
+ if (result)
+ {
+ ShBuiltInResources resources;
+ ShInitBuiltInResources(&resources);
+ Context *context = getContext();
+
+ resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
+ resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
+ resources.MaxVaryingVectors = context->getMaximumVaryingVectors();
+ resources.MaxVertexTextureImageUnits = context->getMaximumVertexTextureImageUnits();
+ resources.MaxCombinedTextureImageUnits = context->getMaximumCombinedTextureImageUnits();
+ resources.MaxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS;
+ resources.MaxFragmentUniformVectors = context->getMaximumFragmentUniformVectors();
+ resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
+ resources.OES_standard_derivatives = 1;
+
+ mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
+ mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
+ }
+ }
+
+ mRefCount = 0;
+ mDeleteStatus = false;
+}
+
+Shader::~Shader()
+{
+ delete[] mSource;
+ delete[] mHlsl;
+ delete[] mInfoLog;
+}
+
+GLuint Shader::getHandle() const
+{
+ return mHandle;
+}
+
+void Shader::setSource(GLsizei count, const char **string, const GLint *length)
+{
+ delete[] mSource;
+ int totalLength = 0;
+
+ for (int i = 0; i < count; i++)
+ {
+ if (length && length[i] >= 0)
+ {
+ totalLength += length[i];
+ }
+ else
+ {
+ totalLength += (int)strlen(string[i]);
+ }
+ }
+
+ mSource = new char[totalLength + 1];
+ char *code = mSource;
+
+ for (int i = 0; i < count; i++)
+ {
+ int stringLength;
+
+ if (length && length[i] >= 0)
+ {
+ stringLength = length[i];
+ }
+ else
+ {
+ stringLength = (int)strlen(string[i]);
+ }
+
+ strncpy(code, string[i], stringLength);
+ code += stringLength;
+ }
+
+ mSource[totalLength] = '\0';
+}
+
+int Shader::getInfoLogLength() const
+{
+ if (!mInfoLog)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mInfoLog) + 1;
+ }
+}
+
+void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+ int index = 0;
+
+ if (mInfoLog)
+ {
+ while (index < bufSize - 1 && index < (int)strlen(mInfoLog))
+ {
+ infoLog[index] = mInfoLog[index];
+ index++;
+ }
+ }
+
+ if (bufSize)
+ {
+ infoLog[index] = '\0';
+ }
+
+ if (length)
+ {
+ *length = index;
+ }
+}
+
+int Shader::getSourceLength() const
+{
+ if (!mSource)
+ {
+ return 0;
+ }
+ else
+ {
+ return strlen(mSource) + 1;
+ }
+}
+
+void Shader::getSource(GLsizei bufSize, GLsizei *length, char *source)
+{
+ int index = 0;
+
+ if (mSource)
+ {
+ while (index < bufSize - 1 && index < (int)strlen(mSource))
+ {
+ source[index] = mSource[index];
+ index++;
+ }
+ }
+
+ if (bufSize)
+ {
+ source[index] = '\0';
+ }
+
+ if (length)
+ {
+ *length = index;
+ }
+}
+
+bool Shader::isCompiled()
+{
+ return mHlsl != NULL;
+}
+
+const char *Shader::getHLSL()
+{
+ return mHlsl;
+}
+
+void Shader::addRef()
+{
+ mRefCount++;
+}
+
+void Shader::release()
+{
+ mRefCount--;
+
+ if (mRefCount == 0 && mDeleteStatus)
+ {
+ mResourceManager->deleteShader(mHandle);
+ }
+}
+
+unsigned int Shader::getRefCount() const
+{
+ return mRefCount;
+}
+
+bool Shader::isFlaggedForDeletion() const
+{
+ return mDeleteStatus;
+}
+
+void Shader::flagForDeletion()
+{
+ mDeleteStatus = true;
+}
+
+void Shader::releaseCompiler()
+{
+ ShDestruct(mFragmentCompiler);
+ ShDestruct(mVertexCompiler);
+
+ mFragmentCompiler = NULL;
+ mVertexCompiler = NULL;
+
+ ShFinalize();
+}
+
+void Shader::parseVaryings()
+{
+ if (mHlsl)
+ {
+ const char *input = strstr(mHlsl, "// Varyings") + 12;
+
+ while(true)
+ {
+ char varyingType[256];
+ char varyingName[256];
+
+ int matches = sscanf(input, "static %255s %255s", varyingType, varyingName);
+
+ if (matches != 2)
+ {
+ break;
+ }
+
+ char *array = strstr(varyingName, "[");
+ int size = 1;
+
+ if (array)
+ {
+ size = atoi(array + 1);
+ *array = '\0';
+ }
+
+ varyings.push_back(Varying(parseType(varyingType), varyingName, size, array != NULL));
+
+ input = strstr(input, ";") + 2;
+ }
+
+ mUsesFragCoord = strstr(mHlsl, "GL_USES_FRAG_COORD") != NULL;
+ mUsesFrontFacing = strstr(mHlsl, "GL_USES_FRONT_FACING") != NULL;
+ mUsesPointSize = strstr(mHlsl, "GL_USES_POINT_SIZE") != NULL;
+ mUsesPointCoord = strstr(mHlsl, "GL_USES_POINT_COORD") != NULL;
+ }
+}
+
+void Shader::compileToHLSL(void *compiler)
+{
+ if (isCompiled() || !mSource)
+ {
+ return;
+ }
+
+ delete[] mInfoLog;
+ mInfoLog = NULL;
+
+ int compileOptions = SH_OBJECT_CODE;
+ std::string sourcePath;
+ if (perfActive())
+ {
+ sourcePath = getTempPath();
+ writeFile(sourcePath.c_str(), mSource, strlen(mSource));
+ compileOptions |= SH_LINE_DIRECTIVES;
+ }
+
+ int result;
+ if (sourcePath.empty())
+ {
+ result = ShCompile(compiler, &mSource, 1, compileOptions);
+ }
+ else
+ {
+ const char* sourceStrings[2] =
+ {
+ sourcePath.c_str(),
+ mSource
+ };
+
+ result = ShCompile(compiler, sourceStrings, 2, compileOptions | SH_SOURCE_PATH);
+ }
+
+ if (result)
+ {
+ int objCodeLen = 0;
+ ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &objCodeLen);
+ mHlsl = new char[objCodeLen];
+ ShGetObjectCode(compiler, mHlsl);
+ }
+ else
+ {
+ int infoLogLen = 0;
+ ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &infoLogLen);
+ mInfoLog = new char[infoLogLen];
+ ShGetInfoLog(compiler, mInfoLog);
+
+ TRACE("\n%s", mInfoLog);
+ }
+}
+
+GLenum Shader::parseType(const std::string &type)
+{
+ if (type == "float")
+ {
+ return GL_FLOAT;
+ }
+ else if (type == "float2")
+ {
+ return GL_FLOAT_VEC2;
+ }
+ else if (type == "float3")
+ {
+ return GL_FLOAT_VEC3;
+ }
+ else if (type == "float4")
+ {
+ return GL_FLOAT_VEC4;
+ }
+ else if (type == "float2x2")
+ {
+ return GL_FLOAT_MAT2;
+ }
+ else if (type == "float3x3")
+ {
+ return GL_FLOAT_MAT3;
+ }
+ else if (type == "float4x4")
+ {
+ return GL_FLOAT_MAT4;
+ }
+ else UNREACHABLE();
+
+ return GL_NONE;
+}
+
+// true if varying x has a higher priority in packing than y
+bool Shader::compareVarying(const Varying &x, const Varying &y)
+{
+ if(x.type == y.type)
+ {
+ return x.size > y.size;
+ }
+
+ switch (x.type)
+ {
+ case GL_FLOAT_MAT4: return true;
+ case GL_FLOAT_MAT2:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return true;
+ case GL_FLOAT_VEC4: return true;
+ case GL_FLOAT_MAT3: return true;
+ case GL_FLOAT_VEC3: return true;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT_VEC4:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return false;
+ case GL_FLOAT_VEC4: return true;
+ case GL_FLOAT_MAT3: return true;
+ case GL_FLOAT_VEC3: return true;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT_MAT3:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return false;
+ case GL_FLOAT_VEC4: return false;
+ case GL_FLOAT_MAT3: return true;
+ case GL_FLOAT_VEC3: return true;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT_VEC3:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return false;
+ case GL_FLOAT_VEC4: return false;
+ case GL_FLOAT_MAT3: return false;
+ case GL_FLOAT_VEC3: return true;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT_VEC2:
+ switch(y.type)
+ {
+ case GL_FLOAT_MAT4: return false;
+ case GL_FLOAT_MAT2: return false;
+ case GL_FLOAT_VEC4: return false;
+ case GL_FLOAT_MAT3: return false;
+ case GL_FLOAT_VEC3: return false;
+ case GL_FLOAT_VEC2: return true;
+ case GL_FLOAT: return true;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT: return false;
+ default: UNREACHABLE();
+ }
+
+ return false;
+}
+
+VertexShader::VertexShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
+{
+}
+
+VertexShader::~VertexShader()
+{
+}
+
+GLenum VertexShader::getType()
+{
+ return GL_VERTEX_SHADER;
+}
+
+void VertexShader::compile()
+{
+ compileToHLSL(mVertexCompiler);
+ parseAttributes();
+ parseVaryings();
+}
+
+int VertexShader::getSemanticIndex(const std::string &attributeName)
+{
+ if (!attributeName.empty())
+ {
+ int semanticIndex = 0;
+ for (AttributeArray::iterator attribute = mAttributes.begin(); attribute != mAttributes.end(); attribute++)
+ {
+ if (attribute->name == attributeName)
+ {
+ return semanticIndex;
+ }
+
+ semanticIndex += VariableRowCount(attribute->type);
+ }
+ }
+
+ return -1;
+}
+
+void VertexShader::parseAttributes()
+{
+ if (mHlsl)
+ {
+ const char *input = strstr(mHlsl, "// Attributes") + 14;
+
+ while(true)
+ {
+ char attributeType[256];
+ char attributeName[256];
+
+ int matches = sscanf(input, "static %255s _%255s", attributeType, attributeName);
+
+ if (matches != 2)
+ {
+ break;
+ }
+
+ mAttributes.push_back(Attribute(parseType(attributeType), attributeName));
+
+ input = strstr(input, ";") + 2;
+ }
+ }
+}
+
+FragmentShader::FragmentShader(ResourceManager *manager, GLuint handle) : Shader(manager, handle)
+{
+}
+
+FragmentShader::~FragmentShader()
+{
+}
+
+GLenum FragmentShader::getType()
+{
+ return GL_FRAGMENT_SHADER;
+}
+
+void FragmentShader::compile()
+{
+ compileToHLSL(mFragmentCompiler);
+ parseVaryings();
+ varyings.sort(compareVarying);
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.h
new file mode 100644
index 000000000..535b42d8c
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Shader.h
@@ -0,0 +1,157 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Shader.h: Defines the abstract gl::Shader class and its concrete derived
+// classes VertexShader and FragmentShader. Implements GL shader objects and
+// related functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section
+// 3.8 page 84.
+
+#ifndef LIBGLESV2_SHADER_H_
+#define LIBGLESV2_SHADER_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <d3dx9.h>
+#include <list>
+#include <vector>
+
+#include "libGLESv2/ResourceManager.h"
+
+namespace gl
+{
+struct Varying
+{
+ Varying(GLenum type, const std::string &name, int size, bool array)
+ : type(type), name(name), size(size), array(array), reg(-1), col(-1)
+ {
+ }
+
+ GLenum type;
+ std::string name;
+ int size; // Number of 'type' elements
+ bool array;
+
+ int reg; // First varying register, assigned during link
+ int col; // First register element, assigned during link
+};
+
+typedef std::list<Varying> VaryingList;
+
+class Shader
+{
+ friend Program;
+
+ public:
+ Shader(ResourceManager *manager, GLuint handle);
+
+ virtual ~Shader();
+
+ virtual GLenum getType() = 0;
+ GLuint getHandle() const;
+
+ void deleteSource();
+ void setSource(GLsizei count, const char **string, const GLint *length);
+ int getInfoLogLength() const;
+ void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+ int getSourceLength() const;
+ void getSource(GLsizei bufSize, GLsizei *length, char *source);
+
+ virtual void compile() = 0;
+ bool isCompiled();
+ const char *getHLSL();
+
+ void addRef();
+ void release();
+ unsigned int getRefCount() const;
+ bool isFlaggedForDeletion() const;
+ void flagForDeletion();
+
+ static void releaseCompiler();
+
+ protected:
+ DISALLOW_COPY_AND_ASSIGN(Shader);
+
+ void parseVaryings();
+
+ void compileToHLSL(void *compiler);
+
+ static GLenum parseType(const std::string &type);
+ static bool compareVarying(const Varying &x, const Varying &y);
+
+ const GLuint mHandle;
+ unsigned int mRefCount; // Number of program objects this shader is attached to
+ bool mDeleteStatus; // Flag to indicate that the shader can be deleted when no longer in use
+
+ char *mSource;
+ char *mHlsl;
+ char *mInfoLog;
+
+ VaryingList varyings;
+
+ bool mUsesFragCoord;
+ bool mUsesFrontFacing;
+ bool mUsesPointSize;
+ bool mUsesPointCoord;
+
+ ResourceManager *mResourceManager;
+
+ static void *mFragmentCompiler;
+ static void *mVertexCompiler;
+};
+
+struct Attribute
+{
+ Attribute() : type(GL_NONE), name("")
+ {
+ }
+
+ Attribute(GLenum type, const std::string &name) : type(type), name(name)
+ {
+ }
+
+ GLenum type;
+ std::string name;
+};
+
+typedef std::vector<Attribute> AttributeArray;
+
+class VertexShader : public Shader
+{
+ friend Program;
+
+ public:
+ VertexShader(ResourceManager *manager, GLuint handle);
+
+ ~VertexShader();
+
+ virtual GLenum getType();
+ virtual void compile();
+ int getSemanticIndex(const std::string &attributeName);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexShader);
+
+ void parseAttributes();
+
+ AttributeArray mAttributes;
+};
+
+class FragmentShader : public Shader
+{
+ public:
+ FragmentShader(ResourceManager *manager, GLuint handle);
+
+ ~FragmentShader();
+
+ virtual GLenum getType();
+ virtual void compile();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FragmentShader);
+};
+}
+
+#endif // LIBGLESV2_SHADER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp
new file mode 100644
index 000000000..bb4c4b8f5
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.cpp
@@ -0,0 +1,2589 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Texture.cpp: Implements the gl::Texture class and its derived classes
+// Texture2D and TextureCubeMap. Implements GL texture objects and related
+// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
+
+#include "libGLESv2/Texture.h"
+
+#include <d3dx9tex.h>
+
+#include <algorithm>
+#include <intrin.h>
+
+#include "common/debug.h"
+
+#include "libEGL/Display.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/Blit.h"
+#include "libGLESv2/Framebuffer.h"
+
+namespace gl
+{
+unsigned int Texture::mCurrentSerial = 1;
+
+Texture::Image::Image()
+ : width(0), height(0), dirty(false), surface(NULL), format(GL_NONE), type(GL_UNSIGNED_BYTE)
+{
+}
+
+Texture::Image::~Image()
+{
+ if (surface)
+ {
+ surface->Release();
+ }
+}
+
+bool Texture::Image::isRenderable() const
+{
+ switch(getD3DFormat())
+ {
+ case D3DFMT_L8:
+ case D3DFMT_A8L8:
+ case D3DFMT_DXT1:
+ return false;
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A16B16G16R16F:
+ case D3DFMT_A32B32G32R32F:
+ return true;
+ default:
+ UNREACHABLE();
+ }
+
+ return false;
+}
+
+D3DFORMAT Texture::Image::getD3DFormat() const
+{
+ if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
+ {
+ return D3DFMT_DXT1;
+ }
+ else if (type == GL_FLOAT)
+ {
+ return D3DFMT_A32B32G32R32F;
+ }
+ else if (type == GL_HALF_FLOAT_OES)
+ {
+ return D3DFMT_A16B16G16R16F;
+ }
+ else if (type == GL_UNSIGNED_BYTE)
+ {
+ if (format == GL_LUMINANCE && getContext()->supportsLuminanceTextures())
+ {
+ return D3DFMT_L8;
+ }
+ else if (format == GL_LUMINANCE_ALPHA && getContext()->supportsLuminanceAlphaTextures())
+ {
+ return D3DFMT_A8L8;
+ }
+ else if (format == GL_RGB)
+ {
+ return D3DFMT_X8R8G8B8;
+ }
+
+ return D3DFMT_A8R8G8B8;
+ }
+
+ return D3DFMT_A8R8G8B8;
+}
+
+Texture::Texture(GLuint id) : RefCountObject(id), mSerial(issueSerial())
+{
+ mMinFilter = GL_NEAREST_MIPMAP_LINEAR;
+ mMagFilter = GL_LINEAR;
+ mWrapS = GL_REPEAT;
+ mWrapT = GL_REPEAT;
+ mDirtyParameter = true;
+
+ mDirtyImage = true;
+
+ mIsRenderable = false;
+}
+
+Texture::~Texture()
+{
+}
+
+Blit *Texture::getBlitter()
+{
+ Context *context = getContext();
+ return context->getBlitter();
+}
+
+// Returns true on successful filter state update (valid enum parameter)
+bool Texture::setMinFilter(GLenum filter)
+{
+ switch (filter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ {
+ if (mMinFilter != filter)
+ {
+ mMinFilter = filter;
+ mDirtyParameter = true;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful filter state update (valid enum parameter)
+bool Texture::setMagFilter(GLenum filter)
+{
+ switch (filter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ {
+ if (mMagFilter != filter)
+ {
+ mMagFilter = filter;
+ mDirtyParameter = true;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful wrap state update (valid enum parameter)
+bool Texture::setWrapS(GLenum wrap)
+{
+ switch (wrap)
+ {
+ case GL_REPEAT:
+ case GL_CLAMP_TO_EDGE:
+ case GL_MIRRORED_REPEAT:
+ {
+ if (mWrapS != wrap)
+ {
+ mWrapS = wrap;
+ mDirtyParameter = true;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+// Returns true on successful wrap state update (valid enum parameter)
+bool Texture::setWrapT(GLenum wrap)
+{
+ switch (wrap)
+ {
+ case GL_REPEAT:
+ case GL_CLAMP_TO_EDGE:
+ case GL_MIRRORED_REPEAT:
+ {
+ if (mWrapT != wrap)
+ {
+ mWrapT = wrap;
+ mDirtyParameter = true;
+ }
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+GLenum Texture::getMinFilter() const
+{
+ return mMinFilter;
+}
+
+GLenum Texture::getMagFilter() const
+{
+ return mMagFilter;
+}
+
+GLenum Texture::getWrapS() const
+{
+ return mWrapS;
+}
+
+GLenum Texture::getWrapT() const
+{
+ return mWrapT;
+}
+
+// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input
+// into the target pixel rectangle at output with outputPitch bytes in between each line.
+void Texture::loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLint unpackAlignment, const void *input, size_t outputPitch, void *output, D3DSURFACE_DESC *description) const
+{
+ GLsizei inputPitch = -ComputePitch(width, format, type, unpackAlignment);
+ input = ((char*)input) - inputPitch * (height - 1);
+
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ switch (format)
+ {
+ case GL_ALPHA:
+ loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_L8);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output, description->Format == D3DFMT_A8L8);
+ break;
+ case GL_RGB:
+ loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGBA:
+ if (supportsSSE2())
+ {
+ loadRGBAUByteImageDataSSE2(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ }
+ else
+ {
+ loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ }
+ break;
+ case GL_BGRA_EXT:
+ loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_5_6_5:
+ switch (format)
+ {
+ case GL_RGB:
+ loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ switch (format)
+ {
+ case GL_RGBA:
+ loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ switch (format)
+ {
+ case GL_RGBA:
+ loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_FLOAT:
+ switch (format)
+ {
+ // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
+ case GL_ALPHA:
+ loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGB:
+ loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGBA:
+ loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_HALF_FLOAT_OES:
+ switch (format)
+ {
+ // float textures are converted to RGBA, not BGRA, as they're stored that way in D3D
+ case GL_ALPHA:
+ loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE:
+ loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_LUMINANCE_ALPHA:
+ loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGB:
+ loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ case GL_RGBA:
+ loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, outputPitch, output);
+ break;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+void Texture::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = 0;
+ dest[4 * x + 1] = 0;
+ dest[4 * x + 2] = 0;
+ dest[4 * x + 3] = source[x];
+ }
+ }
+}
+
+void Texture::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = 0;
+ dest[4 * x + 1] = 0;
+ dest[4 * x + 2] = 0;
+ dest[4 * x + 3] = source[x];
+ }
+ }
+}
+
+void Texture::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = 0;
+ dest[4 * x + 1] = 0;
+ dest[4 * x + 2] = 0;
+ dest[4 * x + 3] = source[x];
+ }
+ }
+}
+
+void Texture::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
+{
+ const int destBytesPerPixel = native? 1: 4;
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
+
+ if (!native) // BGRA8 destination format
+ {
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x];
+ dest[4 * x + 1] = source[x];
+ dest[4 * x + 2] = source[x];
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+ else // L8 destination format
+ {
+ memcpy(dest, source, width);
+ }
+ }
+}
+
+void Texture::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x];
+ dest[4 * x + 1] = source[x];
+ dest[4 * x + 2] = source[x];
+ dest[4 * x + 3] = 1.0f;
+ }
+ }
+}
+
+void Texture::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x];
+ dest[4 * x + 1] = source[x];
+ dest[4 * x + 2] = source[x];
+ dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
+ }
+ }
+}
+
+void Texture::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const
+{
+ const int destBytesPerPixel = native? 2: 4;
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * destBytesPerPixel;
+
+ if (!native) // BGRA8 destination format
+ {
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[2*x+0];
+ dest[4 * x + 1] = source[2*x+0];
+ dest[4 * x + 2] = source[2*x+0];
+ dest[4 * x + 3] = source[2*x+1];
+ }
+ }
+ else
+ {
+ memcpy(dest, source, width * 2);
+ }
+ }
+}
+
+void Texture::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[2*x+0];
+ dest[4 * x + 1] = source[2*x+0];
+ dest[4 * x + 2] = source[2*x+0];
+ dest[4 * x + 3] = source[2*x+1];
+ }
+ }
+}
+
+void Texture::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[2*x+0];
+ dest[4 * x + 1] = source[2*x+0];
+ dest[4 * x + 2] = source[2*x+0];
+ dest[4 * x + 3] = source[2*x+1];
+ }
+ }
+}
+
+void Texture::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 2];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 0];
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+}
+
+void Texture::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2);
+ dest[4 * x + 1] = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9);
+ dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+ dest[4 * x + 3] = 0xFF;
+ }
+ }
+}
+
+void Texture::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 0];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 2];
+ dest[4 * x + 3] = 1.0f;
+ }
+ }
+}
+
+void Texture::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned short *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+ for (int x = 0; x < width; x++)
+ {
+ dest[4 * x + 0] = source[x * 3 + 0];
+ dest[4 * x + 1] = source[x * 3 + 1];
+ dest[4 * x + 2] = source[x * 3 + 2];
+ dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1
+ }
+ }
+}
+
+void Texture::loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned int *source = NULL;
+ unsigned int *dest = NULL;
+ __m128i brMask = _mm_set1_epi32(0x00ff00ff);
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
+ int x = 0;
+
+ // Make output writes aligned
+ for (x = 0; ((reinterpret_cast<intptr_t>(&dest[x]) & 15) != 0) && x < width; x++)
+ {
+ unsigned int rgba = source[x];
+ dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
+ }
+
+ for (; x + 3 < width; x += 4)
+ {
+ __m128i sourceData = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&source[x]));
+ // Mask out g and a, which don't change
+ __m128i gaComponents = _mm_andnot_si128(brMask, sourceData);
+ // Mask out b and r
+ __m128i brComponents = _mm_and_si128(sourceData, brMask);
+ // Swap b and r
+ __m128i brSwapped = _mm_shufflehi_epi16(_mm_shufflelo_epi16(brComponents, _MM_SHUFFLE(2, 3, 0, 1)), _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i result = _mm_or_si128(gaComponents, brSwapped);
+ _mm_store_si128(reinterpret_cast<__m128i*>(&dest[x]), result);
+ }
+
+ // Perform leftover writes
+ for (; x < width; x++)
+ {
+ unsigned int rgba = source[x];
+ dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
+ }
+ }
+}
+
+void Texture::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned int *source = NULL;
+ unsigned int *dest = NULL;
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4);
+
+ for (int x = 0; x < width; x++)
+ {
+ unsigned int rgba = source[x];
+ dest[x] = (_rotl(rgba, 16) & 0x00ff00ff) | (rgba & 0xff00ff00);
+ }
+ }
+}
+
+void Texture::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4);
+ dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8);
+ dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12);
+ dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0);
+ }
+ }
+}
+
+void Texture::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned short *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ for (int x = 0; x < width; x++)
+ {
+ unsigned short rgba = source[x];
+ dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3);
+ dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8);
+ dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13);
+ dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0;
+ }
+ }
+}
+
+void Texture::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const float *source = NULL;
+ float *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ dest = reinterpret_cast<float*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 16);
+ memcpy(dest, source, width * 16);
+ }
+}
+
+void Texture::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8;
+ memcpy(dest, source, width * 8);
+ }
+}
+
+void Texture::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ const unsigned char *source = NULL;
+ unsigned char *dest = NULL;
+
+ for (int y = 0; y < height; y++)
+ {
+ source = static_cast<const unsigned char*>(input) + y * inputPitch;
+ dest = static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 4;
+ memcpy(dest, source, width*4);
+ }
+}
+
+void Texture::loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const
+{
+ ASSERT(xoffset % 4 == 0);
+ ASSERT(yoffset % 4 == 0);
+ ASSERT(width % 4 == 0 || width == 2 || width == 1);
+ ASSERT(inputPitch % 8 == 0);
+ ASSERT(outputPitch % 8 == 0);
+
+ const unsigned int *source = reinterpret_cast<const unsigned int*>(input);
+ unsigned int *dest = reinterpret_cast<unsigned int*>(output);
+
+ switch (height)
+ {
+ case 1:
+ // Round width up in case it is 1.
+ for (int x = 0; x < (width + 1) / 2; x += 2)
+ {
+ // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
+ dest[x] = source[x];
+
+ // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 3 rows being unused. No flipping should occur.
+ dest[x + 1] = source[x + 1];
+ }
+ break;
+ case 2:
+ // Round width up in case it is 1.
+ for (int x = 0; x < (width + 1) / 2; x += 2)
+ {
+ // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
+ dest[x] = source[x];
+
+ // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors, the last 2 rows being unused. Only the top 2 rows should be flipped.
+ dest[x + 1] = ((source[x + 1] << 8) & 0x0000FF00) |
+ ((source[x + 1] >> 8) & 0x000000FF);
+ }
+ break;
+ default:
+ ASSERT(height % 4 == 0);
+ for (int y = 0; y < height / 4; ++y)
+ {
+ const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch);
+ unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(output) + (y + yoffset) * outputPitch + xoffset * 8);
+
+ // Round width up in case it is 1.
+ for (int x = 0; x < (width + 1) / 2; x += 2)
+ {
+ // First 32-bits is two RGB565 colors shared by tile and does not need to be modified.
+ dest[x] = source[x];
+
+ // Second 32-bits contains 4 rows of 4 2-bit interpolants between the colors. All rows should be flipped.
+ dest[x + 1] = (source[x + 1] >> 24) |
+ ((source[x + 1] << 8) & 0x00FF0000) |
+ ((source[x + 1] >> 8) & 0x0000FF00) |
+ (source[x + 1] << 24);
+ }
+ }
+ break;
+ }
+}
+
+void Texture::createSurface(Image *image)
+{
+ IDirect3DTexture9 *newTexture = NULL;
+ IDirect3DSurface9 *newSurface = NULL;
+
+ if (image->width != 0 && image->height != 0)
+ {
+ int levelToFetch = 0;
+ GLsizei requestWidth = image->width;
+ GLsizei requestHeight = image->height;
+ if (IsCompressed(image->format) && (image->width % 4 != 0 || image->height % 4 != 0))
+ {
+ bool isMult4 = false;
+ int upsampleCount = 0;
+ while (!isMult4)
+ {
+ requestWidth <<= 1;
+ requestHeight <<= 1;
+ upsampleCount++;
+ if (requestWidth % 4 == 0 && requestHeight % 4 == 0)
+ {
+ isMult4 = true;
+ }
+ }
+ levelToFetch = upsampleCount;
+ }
+
+ HRESULT result = getDevice()->CreateTexture(requestWidth, requestHeight, levelToFetch + 1, NULL, image->getD3DFormat(),
+ D3DPOOL_SYSTEMMEM, &newTexture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ newTexture->GetSurfaceLevel(levelToFetch, &newSurface);
+ newTexture->Release();
+ }
+
+ if (image->surface)
+ {
+ image->surface->Release();
+ }
+
+ image->surface = newSurface;
+}
+
+void Texture::setImage(GLint unpackAlignment, const void *pixels, Image *image)
+{
+ createSurface(image);
+
+ if (pixels != NULL && image->surface != NULL)
+ {
+ D3DSURFACE_DESC description;
+ image->surface->GetDesc(&description);
+
+ D3DLOCKED_RECT locked;
+ HRESULT result = image->surface->LockRect(&locked, NULL, 0);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ loadImageData(0, 0, image->width, image->height, image->format, image->type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
+ image->surface->UnlockRect();
+ }
+
+ image->dirty = true;
+ mDirtyImage = true;
+ }
+}
+
+void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
+{
+ createSurface(image);
+
+ if (pixels != NULL && image->surface != NULL)
+ {
+ D3DLOCKED_RECT locked;
+ HRESULT result = image->surface->LockRect(&locked, NULL, 0);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ int inputPitch = ComputeCompressedPitch(image->width, image->format);
+ int inputSize = ComputeCompressedSize(image->width, image->height, image->format);
+ loadCompressedImageData(0, 0, image->width, image->height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
+ image->surface->UnlockRect();
+ }
+
+ image->dirty = true;
+ mDirtyImage = true;
+ }
+}
+
+bool Texture::subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image)
+{
+ if (width + xoffset > image->width || height + yoffset > image->height)
+ {
+ error(GL_INVALID_VALUE);
+ return false;
+ }
+
+ if (IsCompressed(image->format))
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ if (format != image->format)
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ if (!image->surface)
+ {
+ createSurface(image);
+ }
+
+ if (pixels != NULL && image->surface != NULL)
+ {
+ D3DSURFACE_DESC description;
+ image->surface->GetDesc(&description);
+
+ D3DLOCKED_RECT locked;
+ HRESULT result = image->surface->LockRect(&locked, NULL, 0);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ loadImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, format, type, unpackAlignment, pixels, locked.Pitch, locked.pBits, &description);
+ image->surface->UnlockRect();
+ }
+
+ image->dirty = true;
+ mDirtyImage = true;
+ }
+
+ return true;
+}
+
+bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image)
+{
+ if (width + xoffset > image->width || height + yoffset > image->height)
+ {
+ error(GL_INVALID_VALUE);
+ return false;
+ }
+
+ if (format != getInternalFormat())
+ {
+ error(GL_INVALID_OPERATION);
+ return false;
+ }
+
+ if (!image->surface)
+ {
+ createSurface(image);
+ }
+
+ if (pixels != NULL && image->surface != NULL)
+ {
+ RECT updateRegion;
+ updateRegion.left = xoffset;
+ updateRegion.right = xoffset + width;
+ updateRegion.bottom = yoffset + height;
+ updateRegion.top = yoffset;
+
+ D3DLOCKED_RECT locked;
+ HRESULT result = image->surface->LockRect(&locked, &updateRegion, 0);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ int inputPitch = ComputeCompressedPitch(width, format);
+ int inputSize = ComputeCompressedSize(width, height, format);
+ loadCompressedImageData(xoffset, transformPixelYOffset(yoffset, height, image->height), width, height, -inputPitch, static_cast<const char*>(pixels) + inputSize - inputPitch, locked.Pitch, locked.pBits);
+ image->surface->UnlockRect();
+ }
+
+ image->dirty = true;
+ mDirtyImage = true;
+ }
+
+ return true;
+}
+
+// This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
+void Texture::copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget)
+{
+ if (!image->surface)
+ {
+ createSurface(image);
+
+ if (!image->surface)
+ {
+ ERR("Failed to create an image surface.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ IDirect3DDevice9 *device = getDevice();
+ IDirect3DSurface9 *renderTargetData = NULL;
+ D3DSURFACE_DESC description;
+ renderTarget->GetDesc(&description);
+
+ HRESULT result = device->CreateOffscreenPlainSurface(description.Width, description.Height, description.Format, D3DPOOL_SYSTEMMEM, &renderTargetData, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Could not create matching destination surface.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ result = device->GetRenderTargetData(renderTarget, renderTargetData);
+
+ if (FAILED(result))
+ {
+ ERR("GetRenderTargetData unexpectedly failed.");
+ renderTargetData->Release();
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ RECT sourceRect = transformPixelRect(x, y, width, height, description.Height);
+ int destYOffset = transformPixelYOffset(yoffset, height, image->height);
+ RECT destRect = {xoffset, destYOffset, xoffset + width, destYOffset + height};
+
+ if (image->isRenderable())
+ {
+ result = D3DXLoadSurfaceFromSurface(image->surface, NULL, &destRect, renderTargetData, NULL, &sourceRect, D3DX_FILTER_BOX, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Copying surfaces unexpectedly failed.");
+ renderTargetData->Release();
+ return error(GL_OUT_OF_MEMORY);
+ }
+ }
+ else
+ {
+ D3DLOCKED_RECT sourceLock = {0};
+ result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Failed to lock the source surface (rectangle might be invalid).");
+ renderTargetData->Release();
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ D3DLOCKED_RECT destLock = {0};
+ result = image->surface->LockRect(&destLock, &destRect, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Failed to lock the destination surface (rectangle might be invalid).");
+ renderTargetData->UnlockRect();
+ renderTargetData->Release();
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (destLock.pBits && sourceLock.pBits)
+ {
+ unsigned char *source = (unsigned char*)sourceLock.pBits;
+ unsigned char *dest = (unsigned char*)destLock.pBits;
+
+ switch (description.Format)
+ {
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_A8R8G8B8:
+ switch(image->getD3DFormat())
+ {
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ dest[x] = source[x * 4 + 2];
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ dest[x * 2 + 0] = source[x * 4 + 2];
+ dest[x * 2 + 1] = source[x * 4 + 3];
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case D3DFMT_R5G6B5:
+ switch(image->getD3DFormat())
+ {
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0xF8;
+ dest[x] = red | (red >> 5);
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ case D3DFMT_A1R5G5B5:
+ switch(image->getD3DFormat())
+ {
+ case D3DFMT_L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0x7C;
+ dest[x] = (red << 1) | (red >> 4);
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ case D3DFMT_A8L8:
+ for(int y = 0; y < height; y++)
+ {
+ for(int x = 0; x < width; x++)
+ {
+ unsigned char red = source[x * 2 + 1] & 0x7C;
+ dest[x * 2 + 0] = (red << 1) | (red >> 4);
+ dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
+ }
+
+ source += sourceLock.Pitch;
+ dest += destLock.Pitch;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+
+ image->surface->UnlockRect();
+ renderTargetData->UnlockRect();
+ }
+
+ renderTargetData->Release();
+
+ image->dirty = true;
+ mDirtyImage = true;
+}
+
+IDirect3DBaseTexture9 *Texture::getTexture()
+{
+ if (!isComplete())
+ {
+ return NULL;
+ }
+
+ if (!getBaseTexture())
+ {
+ createTexture();
+ }
+
+ updateTexture();
+
+ return getBaseTexture();
+}
+
+bool Texture::isDirtyParameter() const
+{
+ return mDirtyParameter;
+}
+
+bool Texture::isDirtyImage() const
+{
+ return mDirtyImage;
+}
+
+void Texture::resetDirty()
+{
+ mDirtyParameter = false;
+ mDirtyImage = false;
+}
+
+unsigned int Texture::getSerial() const
+{
+ return mSerial;
+}
+
+GLint Texture::creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const
+{
+ if ((isPow2(width) && isPow2(height)) || getContext()->supportsNonPower2Texture())
+ {
+ return maxlevel;
+ }
+ else
+ {
+ // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
+ return 1;
+ }
+}
+
+GLint Texture::creationLevels(GLsizei size, GLint maxlevel) const
+{
+ return creationLevels(size, size, maxlevel);
+}
+
+int Texture::levelCount() const
+{
+ return getBaseTexture() ? getBaseTexture()->GetLevelCount() : 0;
+}
+
+unsigned int Texture::issueSerial()
+{
+ return mCurrentSerial++;
+}
+
+Texture2D::Texture2D(GLuint id) : Texture(id)
+{
+ mTexture = NULL;
+ mSurface = NULL;
+}
+
+Texture2D::~Texture2D()
+{
+ mColorbufferProxy.set(NULL);
+
+ if (mTexture)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ }
+
+ if (mSurface)
+ {
+ mSurface->setBoundTexture(NULL);
+ mSurface = NULL;
+ }
+}
+
+GLenum Texture2D::getTarget() const
+{
+ return GL_TEXTURE_2D;
+}
+
+GLsizei Texture2D::getWidth() const
+{
+ return mImageArray[0].width;
+}
+
+GLsizei Texture2D::getHeight() const
+{
+ return mImageArray[0].height;
+}
+
+GLenum Texture2D::getInternalFormat() const
+{
+ return mImageArray[0].format;
+}
+
+GLenum Texture2D::getType() const
+{
+ return mImageArray[0].type;
+}
+
+D3DFORMAT Texture2D::getD3DFormat() const
+{
+ return mImageArray[0].getD3DFormat();
+}
+
+void Texture2D::redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool forceRedefine)
+{
+ GLsizei textureWidth = mImageArray[0].width;
+ GLsizei textureHeight = mImageArray[0].height;
+ GLenum textureFormat = mImageArray[0].format;
+ GLenum textureType = mImageArray[0].type;
+
+ mImageArray[level].width = width;
+ mImageArray[level].height = height;
+ mImageArray[level].format = format;
+ mImageArray[level].type = type;
+
+ if (!mTexture)
+ {
+ return;
+ }
+
+ bool widthOkay = (textureWidth >> level == width) || (textureWidth >> level == 0 && width == 1);
+ bool heightOkay = (textureHeight >> level == height) || (textureHeight >> level == 0 && height == 1);
+ bool textureOkay = (widthOkay && heightOkay && textureFormat == format && textureType == type);
+
+ if (!textureOkay || forceRedefine || mSurface) // Purge all the levels and the texture.
+ {
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ if (mImageArray[i].surface != NULL)
+ {
+ mImageArray[i].surface->Release();
+ mImageArray[i].surface = NULL;
+ mImageArray[i].dirty = true;
+ }
+ }
+
+ if (mTexture != NULL)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ mDirtyImage = true;
+ mIsRenderable = false;
+ }
+
+ if (mSurface)
+ {
+ mSurface->setBoundTexture(NULL);
+ mSurface = NULL;
+ }
+
+ mColorbufferProxy.set(NULL);
+ }
+}
+
+void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ redefineTexture(level, format, width, height, type, false);
+
+ Texture::setImage(unpackAlignment, pixels, &mImageArray[level]);
+}
+
+void Texture2D::bindTexImage(egl::Surface *surface)
+{
+ GLenum format;
+
+ switch(surface->getFormat())
+ {
+ case D3DFMT_A8R8G8B8:
+ format = GL_RGBA;
+ break;
+ case D3DFMT_X8R8G8B8:
+ format = GL_RGB;
+ break;
+ default:
+ UNIMPLEMENTED();
+ return;
+ }
+
+ redefineTexture(0, format, surface->getWidth(), surface->getHeight(), GL_UNSIGNED_BYTE, true);
+
+ IDirect3DTexture9 *texture = surface->getOffscreenTexture();
+
+ mTexture = texture;
+ mDirtyImage = true;
+ mIsRenderable = true;
+ mSurface = surface;
+ mSurface->setBoundTexture(this);
+}
+
+void Texture2D::releaseTexImage()
+{
+ redefineTexture(0, GL_RGB, 0, 0, GL_UNSIGNED_BYTE, true);
+}
+
+void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+{
+ redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
+
+ Texture::setCompressedImage(imageSize, pixels, &mImageArray[level]);
+}
+
+void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ ASSERT(mImageArray[level].surface != NULL);
+
+ if (level < levelCount())
+ {
+ IDirect3DSurface9 *destLevel = NULL;
+ HRESULT result = mTexture->GetSurfaceLevel(level, &destLevel);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ Image *image = &mImageArray[level];
+
+ RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
+
+ POINT destPoint;
+ destPoint.x = sourceRect.left;
+ destPoint.y = sourceRect.top;
+
+ result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
+ ASSERT(SUCCEEDED(result));
+
+ destLevel->Release();
+
+ image->dirty = false;
+ }
+ }
+}
+
+void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[level]))
+ {
+ commitRect(level, xoffset, yoffset, width, height);
+ }
+}
+
+void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[level]))
+ {
+ commitRect(level, xoffset, yoffset, width, height);
+ }
+}
+
+void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ IDirect3DSurface9 *renderTarget = source->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ redefineTexture(level, format, width, height, GL_UNSIGNED_BYTE, false);
+
+ if (!mImageArray[level].isRenderable())
+ {
+ copyToImage(&mImageArray[level], 0, 0, x, y, width, height, renderTarget);
+ }
+ else
+ {
+ if (!mTexture || !mIsRenderable)
+ {
+ convertToRenderTarget();
+ }
+
+ updateTexture();
+
+ if (width != 0 && height != 0 && level < levelCount())
+ {
+ RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
+ sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
+ sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
+ sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
+ sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
+
+ GLint destYOffset = transformPixelYOffset(0, height, mImageArray[level].height);
+
+ IDirect3DSurface9 *dest;
+ HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
+
+ getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
+ dest->Release();
+ }
+ }
+}
+
+void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ if (xoffset + width > mImageArray[level].width || yoffset + height > mImageArray[level].height)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ IDirect3DSurface9 *renderTarget = source->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ redefineTexture(level, mImageArray[level].format, mImageArray[level].width, mImageArray[level].height, GL_UNSIGNED_BYTE, false);
+
+ if (!mImageArray[level].isRenderable() || (!mTexture && !isComplete()))
+ {
+ copyToImage(&mImageArray[level], xoffset, yoffset, x, y, width, height, renderTarget);
+ }
+ else
+ {
+ if (!mTexture || !mIsRenderable)
+ {
+ convertToRenderTarget();
+ }
+
+ updateTexture();
+
+ if (level < levelCount())
+ {
+ RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
+ sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
+ sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
+ sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
+ sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
+
+ GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[level].height);
+
+ IDirect3DSurface9 *dest;
+ HRESULT hr = mTexture->GetSurfaceLevel(level, &dest);
+
+ getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0].format, xoffset, destYOffset, dest);
+ dest->Release();
+ }
+ }
+}
+
+// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+bool Texture2D::isComplete() const
+{
+ GLsizei width = mImageArray[0].width;
+ GLsizei height = mImageArray[0].height;
+
+ if (width <= 0 || height <= 0)
+ {
+ return false;
+ }
+
+ bool mipmapping = false;
+
+ switch (mMinFilter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ mipmapping = false;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ mipmapping = true;
+ break;
+ default: UNREACHABLE();
+ }
+
+ if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
+ (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
+ {
+ if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
+ {
+ return false;
+ }
+ }
+
+ bool npot = getContext()->supportsNonPower2Texture();
+
+ if (!npot)
+ {
+ if ((getWrapS() != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
+ (getWrapT() != GL_CLAMP_TO_EDGE && !isPow2(height)))
+ {
+ return false;
+ }
+ }
+
+ if (mipmapping)
+ {
+ if (!npot)
+ {
+ if (!isPow2(width) || !isPow2(height))
+ {
+ return false;
+ }
+ }
+
+ int q = log2(std::max(width, height));
+
+ for (int level = 1; level <= q; level++)
+ {
+ if (mImageArray[level].format != mImageArray[0].format)
+ {
+ return false;
+ }
+
+ if (mImageArray[level].type != mImageArray[0].type)
+ {
+ return false;
+ }
+
+ if (mImageArray[level].width != std::max(1, width >> level))
+ {
+ return false;
+ }
+
+ if (mImageArray[level].height != std::max(1, height >> level))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool Texture2D::isCompressed() const
+{
+ return IsCompressed(getInternalFormat());
+}
+
+IDirect3DBaseTexture9 *Texture2D::getBaseTexture() const
+{
+ return mTexture;
+}
+
+// Constructs a Direct3D 9 texture resource from the texture images
+void Texture2D::createTexture()
+{
+ IDirect3DDevice9 *device = getDevice();
+ D3DFORMAT format = mImageArray[0].getD3DFormat();
+ GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
+
+ IDirect3DTexture9 *texture = NULL;
+ HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (mTexture)
+ {
+ mTexture->Release();
+ }
+
+ mTexture = texture;
+ mDirtyImage = true;
+ mIsRenderable = false;
+}
+
+void Texture2D::updateTexture()
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ int levels = levelCount();
+
+ for (int level = 0; level < levels; level++)
+ {
+ if (mImageArray[level].surface && mImageArray[level].dirty)
+ {
+ IDirect3DSurface9 *levelSurface = NULL;
+ HRESULT result = mTexture->GetSurfaceLevel(level, &levelSurface);
+
+ ASSERT(SUCCEEDED(result));
+
+ if (SUCCEEDED(result))
+ {
+ result = device->UpdateSurface(mImageArray[level].surface, NULL, levelSurface, NULL);
+ ASSERT(SUCCEEDED(result));
+
+ levelSurface->Release();
+
+ mImageArray[level].dirty = false;
+ }
+ }
+ }
+}
+
+void Texture2D::convertToRenderTarget()
+{
+ IDirect3DTexture9 *texture = NULL;
+
+ if (mImageArray[0].width != 0 && mImageArray[0].height != 0)
+ {
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+ D3DFORMAT format = mImageArray[0].getD3DFormat();
+ GLint levels = creationLevels(mImageArray[0].width, mImageArray[0].height, 0);
+
+ HRESULT result = device->CreateTexture(mImageArray[0].width, mImageArray[0].height, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (mTexture != NULL)
+ {
+ int levels = levelCount();
+ for (int i = 0; i < levels; i++)
+ {
+ IDirect3DSurface9 *source;
+ result = mTexture->GetSurfaceLevel(i, &source);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ IDirect3DSurface9 *dest;
+ result = texture->GetSurfaceLevel(i, &dest);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+ source->Release();
+
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ display->endScene();
+ result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+ source->Release();
+ dest->Release();
+
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ source->Release();
+ dest->Release();
+ }
+ }
+ }
+
+ if (mTexture != NULL)
+ {
+ mTexture->Release();
+ }
+
+ mTexture = texture;
+ mDirtyImage = true;
+ mIsRenderable = true;
+}
+
+void Texture2D::generateMipmaps()
+{
+ if (!getContext()->supportsNonPower2Texture())
+ {
+ if (!isPow2(mImageArray[0].width) || !isPow2(mImageArray[0].height))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+
+ // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
+ unsigned int q = log2(std::max(mImageArray[0].width, mImageArray[0].height));
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ if (mImageArray[i].surface != NULL)
+ {
+ mImageArray[i].surface->Release();
+ mImageArray[i].surface = NULL;
+ }
+
+ mImageArray[i].width = std::max(mImageArray[0].width >> i, 1);
+ mImageArray[i].height = std::max(mImageArray[0].height >> i, 1);
+ mImageArray[i].format = mImageArray[0].format;
+ mImageArray[i].type = mImageArray[0].type;
+ }
+
+ if (mIsRenderable)
+ {
+ if (mTexture == NULL)
+ {
+ ERR(" failed because mTexture was null.");
+ return;
+ }
+
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ IDirect3DSurface9 *upper = NULL;
+ IDirect3DSurface9 *lower = NULL;
+
+ mTexture->GetSurfaceLevel(i-1, &upper);
+ mTexture->GetSurfaceLevel(i, &lower);
+
+ if (upper != NULL && lower != NULL)
+ {
+ getBlitter()->boxFilter(upper, lower);
+ }
+
+ if (upper != NULL) upper->Release();
+ if (lower != NULL) lower->Release();
+
+ mImageArray[i].dirty = false;
+ }
+ }
+ else
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ createSurface(&mImageArray[i]);
+
+ if (mImageArray[i].surface == NULL)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[i].surface, NULL, NULL, mImageArray[i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
+ {
+ ERR(" failed to load filter %d to %d.", i - 1, i);
+ }
+
+ mImageArray[i].dirty = true;
+ }
+ }
+}
+
+Renderbuffer *Texture2D::getRenderbuffer(GLenum target)
+{
+ if (target != GL_TEXTURE_2D)
+ {
+ return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+ }
+
+ if (mColorbufferProxy.get() == NULL)
+ {
+ mColorbufferProxy.set(new Renderbuffer(id(), new Colorbuffer(this, target)));
+ }
+
+ return mColorbufferProxy.get();
+}
+
+IDirect3DSurface9 *Texture2D::getRenderTarget(GLenum target)
+{
+ ASSERT(target == GL_TEXTURE_2D);
+
+ if (!mIsRenderable)
+ {
+ convertToRenderTarget();
+ }
+
+ if (mTexture == NULL)
+ {
+ return NULL;
+ }
+
+ updateTexture();
+
+ IDirect3DSurface9 *renderTarget = NULL;
+ mTexture->GetSurfaceLevel(0, &renderTarget);
+
+ return renderTarget;
+}
+
+TextureCubeMap::TextureCubeMap(GLuint id) : Texture(id)
+{
+ mTexture = NULL;
+}
+
+TextureCubeMap::~TextureCubeMap()
+{
+ for (int i = 0; i < 6; i++)
+ {
+ mFaceProxies[i].set(NULL);
+ }
+
+ if (mTexture)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ }
+}
+
+GLenum TextureCubeMap::getTarget() const
+{
+ return GL_TEXTURE_CUBE_MAP;
+}
+
+GLsizei TextureCubeMap::getWidth() const
+{
+ return mImageArray[0][0].width;
+}
+
+GLsizei TextureCubeMap::getHeight() const
+{
+ return mImageArray[0][0].height;
+}
+
+GLenum TextureCubeMap::getInternalFormat() const
+{
+ return mImageArray[0][0].format;
+}
+
+GLenum TextureCubeMap::getType() const
+{
+ return mImageArray[0][0].type;
+}
+
+D3DFORMAT TextureCubeMap::getD3DFormat() const
+{
+ return mImageArray[0][0].getD3DFormat();
+}
+
+void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(0, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(1, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(2, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(3, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(4, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ setImage(5, level, width, height, format, type, unpackAlignment, pixels);
+}
+
+void TextureCubeMap::setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
+{
+ redefineTexture(faceIndex(face), level, format, width, height, GL_UNSIGNED_BYTE);
+
+ Texture::setCompressedImage(imageSize, pixels, &mImageArray[faceIndex(face)][level]);
+}
+
+void TextureCubeMap::commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+{
+ int face = faceIndex(faceTarget);
+ ASSERT(mImageArray[face][level].surface != NULL);
+
+ if (level < levelCount())
+ {
+ IDirect3DSurface9 *destLevel = getCubeMapSurface(faceTarget, level);
+ ASSERT(destLevel != NULL);
+
+ if (destLevel != NULL)
+ {
+ Image *image = &mImageArray[face][level];
+
+ RECT sourceRect = transformPixelRect(xoffset, yoffset, width, height, image->height);;
+
+ POINT destPoint;
+ destPoint.x = sourceRect.left;
+ destPoint.y = sourceRect.top;
+
+ HRESULT result = getDevice()->UpdateSurface(image->surface, &sourceRect, destLevel, &destPoint);
+ ASSERT(SUCCEEDED(result));
+
+ destLevel->Release();
+
+ image->dirty = false;
+ }
+ }
+}
+
+void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ if (Texture::subImage(xoffset, yoffset, width, height, format, type, unpackAlignment, pixels, &mImageArray[faceIndex(target)][level]))
+ {
+ commitRect(target, level, xoffset, yoffset, width, height);
+ }
+}
+
+void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
+{
+ if (Texture::subImageCompressed(xoffset, yoffset, width, height, format, imageSize, pixels, &mImageArray[faceIndex(target)][level]))
+ {
+ commitRect(target, level, xoffset, yoffset, width, height);
+ }
+}
+
+// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
+bool TextureCubeMap::isComplete() const
+{
+ int size = mImageArray[0][0].width;
+
+ if (size <= 0)
+ {
+ return false;
+ }
+
+ bool mipmapping;
+
+ switch (mMinFilter)
+ {
+ case GL_NEAREST:
+ case GL_LINEAR:
+ mipmapping = false;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ case GL_LINEAR_MIPMAP_NEAREST:
+ case GL_NEAREST_MIPMAP_LINEAR:
+ case GL_LINEAR_MIPMAP_LINEAR:
+ mipmapping = true;
+ break;
+ default: UNREACHABLE();
+ }
+
+ for (int face = 0; face < 6; face++)
+ {
+ if (mImageArray[face][0].width != size || mImageArray[face][0].height != size)
+ {
+ return false;
+ }
+ }
+
+ if ((getInternalFormat() == GL_FLOAT && !getContext()->supportsFloatLinearFilter()) ||
+ (getInternalFormat() == GL_HALF_FLOAT_OES && !getContext()->supportsHalfFloatLinearFilter()))
+ {
+ if (mMagFilter != GL_NEAREST || (mMinFilter != GL_NEAREST && mMinFilter != GL_NEAREST_MIPMAP_NEAREST))
+ {
+ return false;
+ }
+ }
+
+ bool npot = getContext()->supportsNonPower2Texture();
+
+ if (!npot)
+ {
+ if ((getWrapS() != GL_CLAMP_TO_EDGE || getWrapT() != GL_CLAMP_TO_EDGE) && !isPow2(size))
+ {
+ return false;
+ }
+ }
+
+ if (mipmapping)
+ {
+ if (!npot)
+ {
+ if (!isPow2(size))
+ {
+ return false;
+ }
+ }
+
+ int q = log2(size);
+
+ for (int face = 0; face < 6; face++)
+ {
+ for (int level = 1; level <= q; level++)
+ {
+ if (mImageArray[face][level].format != mImageArray[0][0].format)
+ {
+ return false;
+ }
+
+ if (mImageArray[face][level].type != mImageArray[0][0].type)
+ {
+ return false;
+ }
+
+ if (mImageArray[face][level].width != std::max(1, size >> level))
+ {
+ return false;
+ }
+
+ ASSERT(mImageArray[face][level].height == mImageArray[face][level].width);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool TextureCubeMap::isCompressed() const
+{
+ return IsCompressed(getInternalFormat());
+}
+
+IDirect3DBaseTexture9 *TextureCubeMap::getBaseTexture() const
+{
+ return mTexture;
+}
+
+// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one
+void TextureCubeMap::createTexture()
+{
+ IDirect3DDevice9 *device = getDevice();
+ D3DFORMAT format = mImageArray[0][0].getD3DFormat();
+ GLint levels = creationLevels(mImageArray[0][0].width, 0);
+
+ IDirect3DCubeTexture9 *texture = NULL;
+ HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, 0, format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (mTexture)
+ {
+ mTexture->Release();
+ }
+
+ mTexture = texture;
+ mDirtyImage = true;
+ mIsRenderable = false;
+}
+
+void TextureCubeMap::updateTexture()
+{
+ IDirect3DDevice9 *device = getDevice();
+
+ for (int face = 0; face < 6; face++)
+ {
+ int levels = levelCount();
+ for (int level = 0; level < levels; level++)
+ {
+ Image *image = &mImageArray[face][level];
+
+ if (image->surface && image->dirty)
+ {
+ IDirect3DSurface9 *levelSurface = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level);
+ ASSERT(levelSurface != NULL);
+
+ if (levelSurface != NULL)
+ {
+ HRESULT result = device->UpdateSurface(image->surface, NULL, levelSurface, NULL);
+ ASSERT(SUCCEEDED(result));
+
+ levelSurface->Release();
+
+ image->dirty = false;
+ }
+ }
+ }
+ }
+}
+
+void TextureCubeMap::convertToRenderTarget()
+{
+ IDirect3DCubeTexture9 *texture = NULL;
+
+ if (mImageArray[0][0].width != 0)
+ {
+ egl::Display *display = getDisplay();
+ IDirect3DDevice9 *device = getDevice();
+ D3DFORMAT format = mImageArray[0][0].getD3DFormat();
+ GLint levels = creationLevels(mImageArray[0][0].width, 0);
+
+ HRESULT result = device->CreateCubeTexture(mImageArray[0][0].width, levels, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &texture, NULL);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (mTexture != NULL)
+ {
+ int levels = levelCount();
+ for (int f = 0; f < 6; f++)
+ {
+ for (int i = 0; i < levels; i++)
+ {
+ IDirect3DSurface9 *source;
+ result = mTexture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &source);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ IDirect3DSurface9 *dest;
+ result = texture->GetCubeMapSurface(static_cast<D3DCUBEMAP_FACES>(f), i, &dest);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+ source->Release();
+
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ display->endScene();
+ result = device->StretchRect(source, NULL, dest, NULL, D3DTEXF_NONE);
+
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+
+ texture->Release();
+ source->Release();
+ dest->Release();
+
+ return error(GL_OUT_OF_MEMORY);
+ }
+ }
+ }
+ }
+ }
+
+ if (mTexture != NULL)
+ {
+ mTexture->Release();
+ }
+
+ mTexture = texture;
+ mDirtyImage = true;
+ mIsRenderable = true;
+}
+
+void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels)
+{
+ redefineTexture(faceIndex, level, format, width, height, type);
+
+ Texture::setImage(unpackAlignment, pixels, &mImageArray[faceIndex][level]);
+}
+
+unsigned int TextureCubeMap::faceIndex(GLenum face)
+{
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
+ META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
+
+ return face - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+}
+
+void TextureCubeMap::redefineTexture(int face, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type)
+{
+ GLsizei textureWidth = mImageArray[0][0].width;
+ GLsizei textureHeight = mImageArray[0][0].height;
+ GLenum textureFormat = mImageArray[0][0].format;
+ GLenum textureType = mImageArray[0][0].type;
+
+ mImageArray[face][level].width = width;
+ mImageArray[face][level].height = height;
+ mImageArray[face][level].format = format;
+ mImageArray[face][level].type = type;
+
+ if (!mTexture)
+ {
+ return;
+ }
+
+ bool sizeOkay = (textureWidth >> level == width);
+ bool textureOkay = (sizeOkay && textureFormat == format && textureType == type);
+
+ if (!textureOkay) // Purge all the levels and the texture.
+ {
+ for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
+ {
+ for (int f = 0; f < 6; f++)
+ {
+ if (mImageArray[f][i].surface != NULL)
+ {
+ mImageArray[f][i].surface->Release();
+ mImageArray[f][i].surface = NULL;
+ mImageArray[f][i].dirty = true;
+ }
+ }
+ }
+
+ if (mTexture != NULL)
+ {
+ mTexture->Release();
+ mTexture = NULL;
+ mDirtyImage = true;
+ mIsRenderable = false;
+ }
+ }
+}
+
+void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ IDirect3DSurface9 *renderTarget = source->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ unsigned int faceindex = faceIndex(target);
+ redefineTexture(faceindex, level, format, width, height, GL_UNSIGNED_BYTE);
+
+ if (!mImageArray[faceindex][level].isRenderable())
+ {
+ copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
+ }
+ else
+ {
+ if (!mTexture || !mIsRenderable)
+ {
+ convertToRenderTarget();
+ }
+
+ updateTexture();
+
+ ASSERT(width == height);
+
+ if (width > 0 && level < levelCount())
+ {
+ RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
+ sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
+ sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
+ sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
+ sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
+
+ GLint destYOffset = transformPixelYOffset(0, height, mImageArray[faceindex][level].width);
+
+ IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
+
+ getBlitter()->copy(source->getRenderTarget(), sourceRect, format, 0, destYOffset, dest);
+ dest->Release();
+ }
+ }
+}
+
+IDirect3DSurface9 *TextureCubeMap::getCubeMapSurface(GLenum face, unsigned int level)
+{
+ if (mTexture == NULL)
+ {
+ UNREACHABLE();
+ return NULL;
+ }
+
+ IDirect3DSurface9 *surface = NULL;
+
+ HRESULT hr = mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(face), level, &surface);
+
+ return (SUCCEEDED(hr)) ? surface : NULL;
+}
+
+void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
+{
+ GLsizei size = mImageArray[faceIndex(target)][level].width;
+
+ if (xoffset + width > size || yoffset + height > size)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ IDirect3DSurface9 *renderTarget = source->getRenderTarget();
+
+ if (!renderTarget)
+ {
+ ERR("Failed to retrieve the render target.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ unsigned int faceindex = faceIndex(target);
+ redefineTexture(faceindex, level, mImageArray[faceindex][level].format, mImageArray[faceindex][level].width, mImageArray[faceindex][level].height, GL_UNSIGNED_BYTE);
+
+ if (!mImageArray[faceindex][level].isRenderable() || (!mTexture && !isComplete()))
+ {
+ copyToImage(&mImageArray[faceindex][level], 0, 0, x, y, width, height, renderTarget);
+ }
+ else
+ {
+ if (!mTexture || !mIsRenderable)
+ {
+ convertToRenderTarget();
+ }
+
+ updateTexture();
+
+ if (level < levelCount())
+ {
+ RECT sourceRect = transformPixelRect(x, y, width, height, source->getColorbuffer()->getHeight());
+ sourceRect.left = clamp(sourceRect.left, 0, source->getColorbuffer()->getWidth());
+ sourceRect.top = clamp(sourceRect.top, 0, source->getColorbuffer()->getHeight());
+ sourceRect.right = clamp(sourceRect.right, 0, source->getColorbuffer()->getWidth());
+ sourceRect.bottom = clamp(sourceRect.bottom, 0, source->getColorbuffer()->getHeight());
+
+ GLint destYOffset = transformPixelYOffset(yoffset, height, mImageArray[faceindex][level].width);
+
+ IDirect3DSurface9 *dest = getCubeMapSurface(target, level);
+
+ getBlitter()->copy(source->getRenderTarget(), sourceRect, mImageArray[0][0].format, xoffset, destYOffset, dest);
+ dest->Release();
+ }
+ }
+}
+
+bool TextureCubeMap::isCubeComplete() const
+{
+ if (mImageArray[0][0].width == 0)
+ {
+ return false;
+ }
+
+ for (unsigned int f = 1; f < 6; f++)
+ {
+ if (mImageArray[f][0].width != mImageArray[0][0].width
+ || mImageArray[f][0].format != mImageArray[0][0].format)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void TextureCubeMap::generateMipmaps()
+{
+ if (!isCubeComplete())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!getContext()->supportsNonPower2Texture())
+ {
+ if (!isPow2(mImageArray[0][0].width))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+
+ // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
+ unsigned int q = log2(mImageArray[0][0].width);
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ if (mImageArray[f][i].surface != NULL)
+ {
+ mImageArray[f][i].surface->Release();
+ mImageArray[f][i].surface = NULL;
+ }
+
+ mImageArray[f][i].width = std::max(mImageArray[f][0].width >> i, 1);
+ mImageArray[f][i].height = mImageArray[f][i].width;
+ mImageArray[f][i].format = mImageArray[f][0].format;
+ mImageArray[f][i].type = mImageArray[f][0].type;
+ }
+ }
+
+ if (mIsRenderable)
+ {
+ if (mTexture == NULL)
+ {
+ return;
+ }
+
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ IDirect3DSurface9 *upper = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i-1);
+ IDirect3DSurface9 *lower = getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + f, i);
+
+ if (upper != NULL && lower != NULL)
+ {
+ getBlitter()->boxFilter(upper, lower);
+ }
+
+ if (upper != NULL) upper->Release();
+ if (lower != NULL) lower->Release();
+
+ mImageArray[f][i].dirty = false;
+ }
+ }
+ }
+ else
+ {
+ for (unsigned int f = 0; f < 6; f++)
+ {
+ for (unsigned int i = 1; i <= q; i++)
+ {
+ createSurface(&mImageArray[f][i]);
+ if (mImageArray[f][i].surface == NULL)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+
+ if (FAILED(D3DXLoadSurfaceFromSurface(mImageArray[f][i].surface, NULL, NULL, mImageArray[f][i - 1].surface, NULL, NULL, D3DX_FILTER_BOX, 0)))
+ {
+ ERR(" failed to load filter %d to %d.", i - 1, i);
+ }
+
+ mImageArray[f][i].dirty = true;
+ }
+ }
+ }
+}
+
+Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target)
+{
+ if (!IsCubemapTextureTarget(target))
+ {
+ return error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
+ }
+
+ unsigned int face = faceIndex(target);
+
+ if (mFaceProxies[face].get() == NULL)
+ {
+ mFaceProxies[face].set(new Renderbuffer(id(), new Colorbuffer(this, target)));
+ }
+
+ return mFaceProxies[face].get();
+}
+
+IDirect3DSurface9 *TextureCubeMap::getRenderTarget(GLenum target)
+{
+ ASSERT(IsCubemapTextureTarget(target));
+
+ if (!mIsRenderable)
+ {
+ convertToRenderTarget();
+ }
+
+ if (mTexture == NULL)
+ {
+ return NULL;
+ }
+
+ updateTexture();
+
+ IDirect3DSurface9 *renderTarget = NULL;
+ mTexture->GetCubeMapSurface(es2dx::ConvertCubeFace(target), 0, &renderTarget);
+
+ return renderTarget;
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.h b/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.h
new file mode 100644
index 000000000..5bdb2fb0f
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Texture.h
@@ -0,0 +1,312 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// Texture.h: Defines the abstract gl::Texture class and its concrete derived
+// classes Texture2D and TextureCubeMap. Implements GL texture objects and
+// related functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
+
+#ifndef LIBGLESV2_TEXTURE_H_
+#define LIBGLESV2_TEXTURE_H_
+
+#include <vector>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <d3d9.h>
+
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/RefCountObject.h"
+#include "libGLESv2/utilities.h"
+#include "common/debug.h"
+
+namespace egl
+{
+class Surface;
+}
+
+namespace gl
+{
+class Blit;
+class Framebuffer;
+
+enum
+{
+ // These are the maximums the implementation can support
+ // The actual GL caps are limited by the device caps
+ // and should be queried from the Context
+ IMPLEMENTATION_MAX_TEXTURE_SIZE = 16384,
+ IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE = 16384,
+
+ IMPLEMENTATION_MAX_TEXTURE_LEVELS = 15 // 1+log2 of MAX_TEXTURE_SIZE
+};
+
+class Texture : public RefCountObject
+{
+ public:
+ explicit Texture(GLuint id);
+
+ virtual ~Texture();
+
+ virtual GLenum getTarget() const = 0;
+
+ bool setMinFilter(GLenum filter);
+ bool setMagFilter(GLenum filter);
+ bool setWrapS(GLenum wrap);
+ bool setWrapT(GLenum wrap);
+
+ GLenum getMinFilter() const;
+ GLenum getMagFilter() const;
+ GLenum getWrapS() const;
+ GLenum getWrapT() const;
+
+ virtual GLsizei getWidth() const = 0;
+ virtual GLsizei getHeight() const = 0;
+ virtual GLenum getInternalFormat() const = 0;
+ virtual GLenum getType() const = 0;
+ virtual D3DFORMAT getD3DFormat() const = 0;
+
+ virtual bool isComplete() const = 0;
+ virtual bool isCompressed() const = 0;
+
+ IDirect3DBaseTexture9 *getTexture();
+ virtual Renderbuffer *getRenderbuffer(GLenum target) = 0;
+
+ virtual void generateMipmaps() = 0;
+ virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source) = 0;
+
+ bool isDirtyParameter() const;
+ bool isDirtyImage() const;
+ void resetDirty();
+ unsigned int getSerial() const;
+
+ static const GLuint INCOMPLETE_TEXTURE_ID = static_cast<GLuint>(-1); // Every texture takes an id at creation time. The value is arbitrary because it is never registered with the resource manager.
+
+ protected:
+ friend class Colorbuffer;
+
+ // Helper structure representing a single image layer
+ struct Image
+ {
+ Image();
+ ~Image();
+
+ bool isRenderable() const;
+ D3DFORMAT getD3DFormat() const;
+
+ GLsizei width;
+ GLsizei height;
+ GLenum format;
+ GLenum type;
+
+ bool dirty;
+
+ IDirect3DSurface9 *surface;
+ };
+
+ void setImage(GLint unpackAlignment, const void *pixels, Image *image);
+ bool subImage(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels, Image *image);
+ void setCompressedImage(GLsizei imageSize, const void *pixels, Image *image);
+ bool subImageCompressed(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels, Image *image);
+ void copyToImage(Image *image, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, IDirect3DSurface9 *renderTarget);
+
+ GLint creationLevels(GLsizei width, GLsizei height, GLint maxlevel) const;
+ GLint creationLevels(GLsizei size, GLint maxlevel) const;
+
+ virtual IDirect3DBaseTexture9 *getBaseTexture() const = 0;
+ virtual void createTexture() = 0;
+ virtual void updateTexture() = 0;
+ virtual void convertToRenderTarget() = 0;
+ virtual IDirect3DSurface9 *getRenderTarget(GLenum target) = 0;
+
+ void createSurface(Image *image);
+
+ Blit *getBlitter();
+
+ int levelCount() const;
+
+ GLenum mMinFilter;
+ GLenum mMagFilter;
+ GLenum mWrapS;
+ GLenum mWrapT;
+ bool mDirtyParameter;
+
+ bool mDirtyImage;
+
+ bool mIsRenderable;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Texture);
+
+ void loadImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ GLint unpackAlignment, const void *input, std::size_t outputPitch, void *output, D3DSURFACE_DESC *description) const;
+
+ void loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const;
+ void loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output, bool native) const;
+ void loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBAUByteImageDataSSE2(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+ void loadCompressedImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ int inputPitch, const void *input, size_t outputPitch, void *output) const;
+
+ static unsigned int issueSerial();
+
+ const unsigned int mSerial;
+
+ static unsigned int mCurrentSerial;
+};
+
+class Texture2D : public Texture
+{
+ public:
+ explicit Texture2D(GLuint id);
+
+ ~Texture2D();
+
+ virtual GLenum getTarget() const;
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
+ virtual GLenum getType() const;
+ virtual D3DFORMAT getD3DFormat() const;
+
+ void setImage(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
+ void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
+ void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+ void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+
+ virtual bool isComplete() const;
+ virtual bool isCompressed() const;
+ virtual void bindTexImage(egl::Surface *surface);
+ virtual void releaseTexImage();
+
+ virtual void generateMipmaps();
+
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Texture2D);
+
+ virtual IDirect3DBaseTexture9 *getBaseTexture() const;
+ virtual void createTexture();
+ virtual void updateTexture();
+ virtual void convertToRenderTarget();
+ virtual IDirect3DSurface9 *getRenderTarget(GLenum target);
+
+ void redefineTexture(GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type, bool force);
+ void commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+
+ Image mImageArray[IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+
+ IDirect3DTexture9 *mTexture;
+ egl::Surface *mSurface;
+
+ BindingPointer<Renderbuffer> mColorbufferProxy;
+};
+
+class TextureCubeMap : public Texture
+{
+ public:
+ explicit TextureCubeMap(GLuint id);
+
+ ~TextureCubeMap();
+
+ virtual GLenum getTarget() const;
+
+ virtual GLsizei getWidth() const;
+ virtual GLsizei getHeight() const;
+ virtual GLenum getInternalFormat() const;
+ virtual GLenum getType() const;
+ virtual D3DFORMAT getD3DFormat() const;
+
+ void setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+
+ void setCompressedImage(GLenum face, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels);
+
+ void subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);
+ void copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+ virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);
+
+ virtual bool isComplete() const;
+ virtual bool isCompressed() const;
+
+ virtual void generateMipmaps();
+
+ virtual Renderbuffer *getRenderbuffer(GLenum target);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureCubeMap);
+
+ virtual IDirect3DBaseTexture9 *getBaseTexture() const;
+ virtual void createTexture();
+ virtual void updateTexture();
+ virtual void convertToRenderTarget();
+ virtual IDirect3DSurface9 *getRenderTarget(GLenum target);
+
+ // face is one of the GL_TEXTURE_CUBE_MAP_* enumerants.
+ // Returns NULL if the call underlying Direct3D call fails.
+ IDirect3DSurface9 *getCubeMapSurface(GLenum face, unsigned int level);
+
+ static unsigned int faceIndex(GLenum face);
+
+ bool isCubeComplete() const;
+
+ void setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);
+ void commitRect(GLenum faceTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+ void redefineTexture(int faceIndex, GLint level, GLenum format, GLsizei width, GLsizei height, GLenum type);
+
+ Image mImageArray[6][IMPLEMENTATION_MAX_TEXTURE_LEVELS];
+
+ IDirect3DCubeTexture9 *mTexture;
+
+ BindingPointer<Renderbuffer> mFaceProxies[6];
+};
+}
+
+#endif // LIBGLESV2_TEXTURE_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.cpp
new file mode 100644
index 000000000..a7716cee0
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.cpp
@@ -0,0 +1,733 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#include "libGLESv2/VertexDataManager.h"
+
+#include "common/debug.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/main.h"
+
+#include "libGLESv2/vertexconversion.h"
+#include "libGLESv2/IndexDataManager.h"
+
+namespace
+{
+ enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
+}
+
+namespace gl
+{
+
+VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device)
+{
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDirtyCurrentValue[i] = true;
+ mCurrentValueBuffer[i] = NULL;
+ }
+
+ const D3DCAPS9 &caps = context->getDeviceCaps();
+ checkVertexCaps(caps.DeclTypes);
+
+ mStreamingBuffer = new StreamingVertexBuffer(mDevice, INITIAL_STREAM_BUFFER_SIZE);
+
+ if (!mStreamingBuffer)
+ {
+ ERR("Failed to allocate the streaming vertex buffer.");
+ }
+}
+
+VertexDataManager::~VertexDataManager()
+{
+ delete mStreamingBuffer;
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ delete mCurrentValueBuffer[i];
+ }
+}
+
+UINT VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
+{
+ Buffer *buffer = attribute.mBoundBuffer.get();
+
+ int inputStride = attribute.stride();
+ int elementSize = attribute.typeSize();
+ const FormatConverter &converter = formatConverter(attribute);
+ UINT streamOffset = 0;
+
+ void *output = NULL;
+
+ if (vertexBuffer)
+ {
+ output = vertexBuffer->map(attribute, spaceRequired(attribute, count), &streamOffset);
+ }
+
+ if (output == NULL)
+ {
+ ERR("Failed to map vertex buffer.");
+ return -1;
+ }
+
+ const char *input = NULL;
+
+ if (buffer)
+ {
+ int offset = attribute.mOffset;
+
+ input = static_cast<const char*>(buffer->data()) + offset;
+ }
+ else
+ {
+ input = static_cast<const char*>(attribute.mPointer);
+ }
+
+ input += inputStride * start;
+
+ if (converter.identity && inputStride == elementSize)
+ {
+ memcpy(output, input, count * inputStride);
+ }
+ else
+ {
+ converter.convertArray(input, inputStride, count, output);
+ }
+
+ vertexBuffer->unmap();
+
+ return streamOffset;
+}
+
+GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
+{
+ if (!mStreamingBuffer)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ const VertexAttributeArray &attribs = mContext->getVertexAttributes();
+ Program *program = mContext->getCurrentProgram();
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ translated[attributeIndex].active = (program->getSemanticIndex(attributeIndex) != -1);
+ }
+
+ // Determine the required storage size per used buffer, and invalidate static buffers that don't contain matching attributes
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+ StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+
+ if (staticBuffer)
+ {
+ if (staticBuffer->size() == 0)
+ {
+ int totalCount = buffer->size() / attribs[i].stride();
+ staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount));
+ }
+ else if (staticBuffer->lookupAttribute(attribs[i]) == -1)
+ {
+ // This static buffer doesn't have matching attributes, so fall back to using the streaming buffer
+ mStreamingBuffer->addRequiredSpaceFor(staticBuffer);
+ buffer->invalidateStaticData();
+
+ mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count));
+ }
+ }
+ else
+ {
+ mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count));
+ }
+ }
+ }
+
+ // Reserve the required space per used buffer
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+ ArrayVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+ ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer;
+
+ if (vertexBuffer)
+ {
+ vertexBuffer->reserveRequiredSpace();
+ }
+ }
+ }
+
+ // Perform the vertex data translations
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active)
+ {
+ if (attribs[i].mArrayEnabled)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (!buffer && attribs[i].mPointer == NULL)
+ {
+ // This is an application error that would normally result in a crash, but we catch it and return an error
+ ERR("An enabled vertex array has no buffer and no pointer.");
+ return GL_INVALID_OPERATION;
+ }
+
+ const FormatConverter &converter = formatConverter(attribs[i]);
+
+ StaticVertexBuffer *staticBuffer = buffer ? buffer->getStaticVertexBuffer() : NULL;
+ ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);
+
+ UINT streamOffset = -1;
+
+ if (staticBuffer)
+ {
+ streamOffset = staticBuffer->lookupAttribute(attribs[i]);
+
+ if (streamOffset == -1)
+ {
+ // Convert the entire buffer
+ int totalCount = buffer->size() / attribs[i].stride();
+ int startIndex = attribs[i].mOffset / attribs[i].stride();
+
+ streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i]);
+ }
+
+ if (streamOffset != -1)
+ {
+ streamOffset += (start + attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize;
+ }
+ }
+ else
+ {
+ streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
+ }
+
+ if (streamOffset == -1)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ translated[i].vertexBuffer = vertexBuffer->getBuffer();
+ translated[i].type = converter.d3dDeclType;
+ translated[i].stride = converter.outputElementSize;
+ translated[i].offset = streamOffset;
+ }
+ else
+ {
+ if (mDirtyCurrentValue[i])
+ {
+ delete mCurrentValueBuffer[i];
+ mCurrentValueBuffer[i] = new ConstantVertexBuffer(mDevice, attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]);
+ mDirtyCurrentValue[i] = false;
+ }
+
+ translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer();
+
+ translated[i].type = D3DDECLTYPE_FLOAT4;
+ translated[i].stride = 0;
+ translated[i].offset = 0;
+ }
+ }
+ }
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active && attribs[i].mArrayEnabled)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (buffer)
+ {
+ buffer->promoteStaticUsage(count * attribs[i].typeSize());
+ }
+ }
+ }
+
+ return GL_NO_ERROR;
+}
+
+std::size_t VertexDataManager::spaceRequired(const VertexAttribute &attrib, std::size_t count) const
+{
+ return formatConverter(attrib).outputElementSize * count;
+}
+
+// Mapping from OpenGL-ES vertex attrib type to D3D decl type:
+//
+// BYTE SHORT (Cast)
+// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
+// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast)
+// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize)
+// SHORT SHORT (Identity)
+// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize)
+// UNSIGNED_SHORT FLOAT (Cast)
+// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize)
+// FIXED (not in WebGL) FLOAT (FixedToFloat)
+// FLOAT FLOAT (Identity)
+
+// GLToCType maps from GL type (as GLenum) to the C typedef.
+template <GLenum GLType> struct GLToCType { };
+
+template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; };
+template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; };
+template <> struct GLToCType<GL_SHORT> { typedef GLshort type; };
+template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; };
+template <> struct GLToCType<GL_FIXED> { typedef GLuint type; };
+template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; };
+
+// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
+enum D3DVertexType
+{
+ D3DVT_FLOAT,
+ D3DVT_SHORT,
+ D3DVT_SHORT_NORM,
+ D3DVT_UBYTE,
+ D3DVT_UBYTE_NORM,
+ D3DVT_USHORT_NORM
+};
+
+// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
+template <unsigned int D3DType> struct D3DToCType { };
+
+template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
+template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
+template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
+template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
+
+// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
+template <unsigned int type, int size>
+struct WidenRule
+{
+};
+
+template <int size> struct WidenRule<D3DVT_FLOAT, size> : gl::NoWiden<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT, size> : gl::WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : gl::WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE, size> : gl::WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : gl::WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : gl::WidenToEven<size> { };
+
+// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
+template <unsigned int d3dtype, int size>
+struct VertexTypeFlags
+{
+};
+
+template <unsigned int capflag, unsigned int declflag>
+struct VertexTypeFlagsHelper
+{
+ enum { capflag = capflag };
+ enum { declflag = declflag };
+};
+
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
+
+
+// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
+template <GLenum GLtype, bool normalized>
+struct VertexTypeMapping
+{
+};
+
+template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
+struct VertexTypeMappingBase
+{
+ enum { preferred = Preferred };
+ enum { fallback = Fallback };
+};
+
+template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast
+template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize
+template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity
+template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat
+template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity
+
+
+// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
+// The conversion rules themselves are defined in vertexconversion.h.
+
+// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
+template <GLenum fromType, bool normalized, unsigned int toType>
+struct ConversionRule : gl::Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type>
+{
+};
+
+// All conversions from normalized types to float use the Normalize operator.
+template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : gl::Normalize<typename GLToCType<fromType>::type> { };
+
+// Use a full specialisation for this so that it preferentially matches ahead of the generic normalize-to-float rules.
+template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
+template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
+
+// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
+// whether it is normalized or not.
+template <class T, bool normalized>
+struct DefaultVertexValuesStage2
+{
+};
+
+template <class T> struct DefaultVertexValuesStage2<T, true> : gl::NormalizedDefaultValues<T> { };
+template <class T> struct DefaultVertexValuesStage2<T, false> : gl::SimpleDefaultValues<T> { };
+
+// Work out the default value rule for a D3D type (expressed as the C type) and
+template <class T, bool normalized>
+struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized>
+{
+};
+
+template <bool normalized> struct DefaultVertexValues<float, normalized> : gl::SimpleDefaultValues<float> { };
+
+// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
+// The fallback conversion produces an output that all D3D9 devices must support.
+template <class T> struct UsePreferred { enum { type = T::preferred }; };
+template <class T> struct UseFallback { enum { type = T::fallback }; };
+
+// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
+// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
+// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
+template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
+struct Converter
+ : gl::VertexDataConverter<typename GLToCType<fromType>::type,
+ WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
+ ConversionRule<fromType,
+ normalized,
+ PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
+ DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
+{
+private:
+ enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
+ enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
+
+public:
+ enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
+ enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
+};
+
+// Initialise a TranslationInfo
+#define TRANSLATION(type, norm, size, preferred) \
+ { \
+ Converter<type, norm, size, preferred>::identity, \
+ Converter<type, norm, size, preferred>::finalSize, \
+ Converter<type, norm, size, preferred>::convertArray, \
+ static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \
+ }
+
+#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \
+ { \
+ Converter<type, norm, size, UsePreferred>::capflag, \
+ TRANSLATION(type, norm, size, UsePreferred), \
+ TRANSLATION(type, norm, size, UseFallback) \
+ }
+
+#define TRANSLATIONS_FOR_TYPE(type) \
+ { \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \
+ }
+
+const VertexDataManager::TranslationDescription VertexDataManager::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
+{
+ TRANSLATIONS_FOR_TYPE(GL_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_SHORT),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
+ TRANSLATIONS_FOR_TYPE(GL_FIXED),
+ TRANSLATIONS_FOR_TYPE(GL_FLOAT)
+};
+
+void VertexDataManager::checkVertexCaps(DWORD declTypes)
+{
+ for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
+ {
+ for (unsigned int j = 0; j < 2; j++)
+ {
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0)
+ {
+ mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion;
+ }
+ else
+ {
+ mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion;
+ }
+ }
+ }
+ }
+}
+
+// This is used to index mAttributeTypes and mPossibleTranslations.
+unsigned int VertexDataManager::typeIndex(GLenum type) const
+{
+ switch (type)
+ {
+ case GL_BYTE: return 0;
+ case GL_UNSIGNED_BYTE: return 1;
+ case GL_SHORT: return 2;
+ case GL_UNSIGNED_SHORT: return 3;
+ case GL_FIXED: return 4;
+ case GL_FLOAT: return 5;
+
+ default: UNREACHABLE(); return 5;
+ }
+}
+
+VertexBuffer::VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : mDevice(device), mVertexBuffer(NULL)
+{
+ if (size > 0)
+ {
+ D3DPOOL pool = getDisplay()->getBufferPool(usageFlags);
+ HRESULT result = device->CreateVertexBuffer(size, usageFlags, 0, pool, &mVertexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", size);
+ }
+ }
+}
+
+VertexBuffer::~VertexBuffer()
+{
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Release();
+ }
+}
+
+void VertexBuffer::unmap()
+{
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Unlock();
+ }
+}
+
+IDirect3DVertexBuffer9 *VertexBuffer::getBuffer() const
+{
+ return mVertexBuffer;
+}
+
+ConstantVertexBuffer::ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w) : VertexBuffer(device, 4 * sizeof(float), D3DUSAGE_WRITEONLY)
+{
+ void *buffer = NULL;
+
+ if (mVertexBuffer)
+ {
+ HRESULT result = mVertexBuffer->Lock(0, 0, &buffer, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ }
+ }
+
+ if (buffer)
+ {
+ float *vector = (float*)buffer;
+
+ vector[0] = x;
+ vector[1] = y;
+ vector[2] = z;
+ vector[3] = w;
+
+ mVertexBuffer->Unlock();
+ }
+}
+
+ConstantVertexBuffer::~ConstantVertexBuffer()
+{
+}
+
+ArrayVertexBuffer::ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : VertexBuffer(device, size, usageFlags)
+{
+ mBufferSize = size;
+ mWritePosition = 0;
+ mRequiredSpace = 0;
+}
+
+ArrayVertexBuffer::~ArrayVertexBuffer()
+{
+}
+
+void ArrayVertexBuffer::addRequiredSpace(UINT requiredSpace)
+{
+ mRequiredSpace += requiredSpace;
+}
+
+void ArrayVertexBuffer::addRequiredSpaceFor(ArrayVertexBuffer *buffer)
+{
+ mRequiredSpace += buffer->mRequiredSpace;
+}
+
+StreamingVertexBuffer::StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize) : ArrayVertexBuffer(device, initialSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)
+{
+}
+
+StreamingVertexBuffer::~StreamingVertexBuffer()
+{
+}
+
+void *StreamingVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mVertexBuffer)
+ {
+ HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StreamingVertexBuffer::reserveRequiredSpace()
+{
+ if (mRequiredSpace > mBufferSize)
+ {
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Release();
+ mVertexBuffer = NULL;
+ }
+
+ mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2); // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations.
+
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
+ HRESULT result = mDevice->CreateVertexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+ else if (mWritePosition + mRequiredSpace > mBufferSize) // Recycle
+ {
+ if (mVertexBuffer)
+ {
+ void *dummy;
+ mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ mVertexBuffer->Unlock();
+ }
+
+ mWritePosition = 0;
+ }
+
+ mRequiredSpace = 0;
+}
+
+StaticVertexBuffer::StaticVertexBuffer(IDirect3DDevice9 *device) : ArrayVertexBuffer(device, 0, D3DUSAGE_WRITEONLY)
+{
+}
+
+StaticVertexBuffer::~StaticVertexBuffer()
+{
+}
+
+void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, UINT *streamOffset)
+{
+ void *mapPtr = NULL;
+
+ if (mVertexBuffer)
+ {
+ HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ int attributeOffset = attribute.mOffset % attribute.stride();
+ VertexElement element = {attribute.mType, attribute.mSize, attribute.mNormalized, attributeOffset, mWritePosition};
+ mCache.push_back(element);
+
+ *streamOffset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StaticVertexBuffer::reserveRequiredSpace()
+{
+ if (!mVertexBuffer && mBufferSize == 0)
+ {
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY);
+ HRESULT result = mDevice->CreateVertexBuffer(mRequiredSpace, D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mRequiredSpace);
+ }
+
+ mBufferSize = mRequiredSpace;
+ }
+ else if (mVertexBuffer && mBufferSize >= mRequiredSpace)
+ {
+ // Already allocated
+ }
+ else UNREACHABLE(); // Static vertex buffers can't be resized
+
+ mRequiredSpace = 0;
+}
+
+UINT StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
+{
+ for (unsigned int element = 0; element < mCache.size(); element++)
+ {
+ if (mCache[element].type == attribute.mType && mCache[element].size == attribute.mSize && mCache[element].normalized == attribute.mNormalized)
+ {
+ if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride())
+ {
+ return mCache[element].streamOffset;
+ }
+ }
+ }
+
+ return -1;
+}
+
+const VertexDataManager::FormatConverter &VertexDataManager::formatConverter(const VertexAttribute &attribute) const
+{
+ return mAttributeTypes[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1];
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.h b/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.h
new file mode 100644
index 000000000..1bd8351d8
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/VertexDataManager.h
@@ -0,0 +1,168 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#ifndef LIBGLESV2_VERTEXDATAMANAGER_H_
+#define LIBGLESV2_VERTEXDATAMANAGER_H_
+
+#include <vector>
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "libGLESv2/Context.h"
+
+namespace gl
+{
+
+struct TranslatedAttribute
+{
+ bool active;
+
+ D3DDECLTYPE type;
+ UINT offset;
+ UINT stride; // 0 means not to advance the read pointer at all
+
+ IDirect3DVertexBuffer9 *vertexBuffer;
+};
+
+class VertexBuffer
+{
+ public:
+ VertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
+ virtual ~VertexBuffer();
+
+ void unmap();
+
+ IDirect3DVertexBuffer9 *getBuffer() const;
+
+ protected:
+ IDirect3DDevice9 *const mDevice;
+ IDirect3DVertexBuffer9 *mVertexBuffer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexBuffer);
+};
+
+class ConstantVertexBuffer : public VertexBuffer
+{
+ public:
+ ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w);
+ ~ConstantVertexBuffer();
+};
+
+class ArrayVertexBuffer : public VertexBuffer
+{
+ public:
+ ArrayVertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
+ ~ArrayVertexBuffer();
+
+ UINT size() const { return mBufferSize; }
+ virtual void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset) = 0;
+ virtual void reserveRequiredSpace() = 0;
+ void addRequiredSpace(UINT requiredSpace);
+ void addRequiredSpaceFor(ArrayVertexBuffer *buffer);
+
+ protected:
+ UINT mBufferSize;
+ UINT mWritePosition;
+ UINT mRequiredSpace;
+};
+
+class StreamingVertexBuffer : public ArrayVertexBuffer
+{
+ public:
+ StreamingVertexBuffer(IDirect3DDevice9 *device, UINT initialSize);
+ ~StreamingVertexBuffer();
+
+ void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
+ void reserveRequiredSpace();
+};
+
+class StaticVertexBuffer : public ArrayVertexBuffer
+{
+ public:
+ explicit StaticVertexBuffer(IDirect3DDevice9 *device);
+ ~StaticVertexBuffer();
+
+ void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
+ void reserveRequiredSpace();
+
+ UINT lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
+
+ private:
+ struct VertexElement
+ {
+ GLenum type;
+ GLint size;
+ bool normalized;
+ int attributeOffset;
+
+ UINT streamOffset;
+ };
+
+ std::vector<VertexElement> mCache;
+};
+
+class VertexDataManager
+{
+ public:
+ VertexDataManager(Context *context, IDirect3DDevice9 *backend);
+ virtual ~VertexDataManager();
+
+ void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; }
+
+ GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexDataManager);
+
+ UINT spaceRequired(const VertexAttribute &attrib, std::size_t count) const;
+ UINT writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
+
+ Context *const mContext;
+ IDirect3DDevice9 *const mDevice;
+
+ StreamingVertexBuffer *mStreamingBuffer;
+
+ bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS];
+ ConstantVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS];
+
+ // Attribute format conversion
+ struct FormatConverter
+ {
+ bool identity;
+ std::size_t outputElementSize;
+ void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out);
+ D3DDECLTYPE d3dDeclType;
+ };
+
+ enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
+
+ FormatConverter mAttributeTypes[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
+
+ struct TranslationDescription
+ {
+ DWORD capsFlag;
+ FormatConverter preferredConversion;
+ FormatConverter fallbackConversion;
+ };
+
+ // This table is used to generate mAttributeTypes.
+ static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
+
+ void checkVertexCaps(DWORD declTypes);
+
+ unsigned int typeIndex(GLenum type) const;
+ const FormatConverter &formatConverter(const VertexAttribute &attribute) const;
+};
+
+}
+
+#endif // LIBGLESV2_VERTEXDATAMANAGER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp
new file mode 100644
index 000000000..f79d60677
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.cpp
@@ -0,0 +1,382 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// geometry/IndexDataManager.cpp: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#include "libGLESv2/geometry/IndexDataManager.h"
+
+#include "common/debug.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/main.h"
+
+namespace
+{
+ enum { INITIAL_INDEX_BUFFER_SIZE = 4096 * sizeof(GLuint) };
+}
+
+namespace gl
+{
+
+IndexDataManager::IndexDataManager(Context *context, IDirect3DDevice9 *device) : mDevice(device)
+{
+ mStreamingBufferShort = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
+
+ if (context->supports32bitIndices())
+ {
+ mStreamingBufferInt = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
+ }
+ else
+ {
+ mStreamingBufferInt = NULL;
+ }
+}
+
+IndexDataManager::~IndexDataManager()
+{
+ delete mStreamingBufferShort;
+ delete mStreamingBufferInt;
+}
+
+void convertIndices(GLenum type, const void *input, GLsizei count, void *output)
+{
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ const GLubyte *in = static_cast<const GLubyte*>(input);
+ GLushort *out = static_cast<GLushort*>(output);
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ out[i] = in[i];
+ }
+ }
+ else if (type == GL_UNSIGNED_INT)
+ {
+ memcpy(output, input, count * sizeof(GLuint));
+ }
+ else if (type == GL_UNSIGNED_SHORT)
+ {
+ memcpy(output, input, count * sizeof(GLushort));
+ }
+ else UNREACHABLE();
+}
+
+template <class IndexType>
+void computeRange(const IndexType *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+{
+ *minIndex = indices[0];
+ *maxIndex = indices[0];
+
+ for (GLsizei i = 0; i < count; i++)
+ {
+ if (*minIndex > indices[i]) *minIndex = indices[i];
+ if (*maxIndex < indices[i]) *maxIndex = indices[i];
+ }
+}
+
+void computeRange(GLenum type, const void *indices, GLsizei count, GLuint *minIndex, GLuint *maxIndex)
+{
+ if (type == GL_UNSIGNED_BYTE)
+ {
+ computeRange(static_cast<const GLubyte*>(indices), count, minIndex, maxIndex);
+ }
+ else if (type == GL_UNSIGNED_INT)
+ {
+ computeRange(static_cast<const GLuint*>(indices), count, minIndex, maxIndex);
+ }
+ else if (type == GL_UNSIGNED_SHORT)
+ {
+ computeRange(static_cast<const GLushort*>(indices), count, minIndex, maxIndex);
+ }
+ else UNREACHABLE();
+}
+
+GLenum IndexDataManager::prepareIndexData(GLenum type, GLsizei count, Buffer *buffer, const void *indices, TranslatedIndexData *translated)
+{
+ D3DFORMAT format = (type == GL_UNSIGNED_INT) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ bool alignedOffset = false;
+
+ if (buffer != NULL)
+ {
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE: alignedOffset = (offset % sizeof(GLubyte) == 0); break;
+ case GL_UNSIGNED_SHORT: alignedOffset = (offset % sizeof(GLushort) == 0); break;
+ case GL_UNSIGNED_INT: alignedOffset = (offset % sizeof(GLuint) == 0); break;
+ default: UNREACHABLE(); alignedOffset = false;
+ }
+
+ if (typeSize(type) * count + offset > static_cast<std::size_t>(buffer->size()))
+ {
+ return GL_INVALID_OPERATION;
+ }
+
+ indices = static_cast<const GLubyte*>(buffer->data()) + offset;
+ }
+
+ StreamingIndexBuffer *streamingBuffer = (type == GL_UNSIGNED_INT) ? mStreamingBufferInt : mStreamingBufferShort;
+
+ StaticIndexBuffer *staticBuffer = buffer ? buffer->getIndexBuffer() : NULL;
+ IndexBuffer *indexBuffer = streamingBuffer;
+ UINT streamOffset = 0;
+
+ if (staticBuffer && staticBuffer->lookupType(type) && alignedOffset)
+ {
+ indexBuffer = staticBuffer;
+ streamOffset = staticBuffer->lookupRange(offset, count, &translated->minIndex, &translated->maxIndex);
+
+ if (streamOffset == -1)
+ {
+ streamOffset = (offset / typeSize(type)) * indexSize(format);
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+ staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
+ }
+ }
+ else
+ {
+ int convertCount = count;
+
+ if (staticBuffer)
+ {
+ if (staticBuffer->size() == 0 && alignedOffset)
+ {
+ indexBuffer = staticBuffer;
+ convertCount = buffer->size() / typeSize(type);
+ }
+ else
+ {
+ buffer->invalidateStaticData();
+ staticBuffer = NULL;
+ }
+ }
+
+ void *output = NULL;
+
+ if (indexBuffer)
+ {
+ indexBuffer->reserveSpace(convertCount * indexSize(format), type);
+ output = indexBuffer->map(indexSize(format) * convertCount, &streamOffset);
+ }
+
+ if (output == NULL)
+ {
+ ERR("Failed to map index buffer.");
+ return GL_OUT_OF_MEMORY;
+ }
+
+ convertIndices(type, staticBuffer ? buffer->data() : indices, convertCount, output);
+ indexBuffer->unmap();
+
+ computeRange(type, indices, count, &translated->minIndex, &translated->maxIndex);
+
+ if (staticBuffer)
+ {
+ streamOffset = (offset / typeSize(type)) * indexSize(format);
+ staticBuffer->addRange(offset, count, translated->minIndex, translated->maxIndex, streamOffset);
+ }
+ }
+
+ translated->indexBuffer = indexBuffer->getBuffer();
+ translated->startIndex = streamOffset / indexSize(format);
+
+ return GL_NO_ERROR;
+}
+
+std::size_t IndexDataManager::indexSize(D3DFORMAT format) const
+{
+ return (format == D3DFMT_INDEX32) ? sizeof(unsigned int) : sizeof(unsigned short);
+}
+
+std::size_t IndexDataManager::typeSize(GLenum type) const
+{
+ switch (type)
+ {
+ case GL_UNSIGNED_INT: return sizeof(GLuint);
+ case GL_UNSIGNED_SHORT: return sizeof(GLushort);
+ case GL_UNSIGNED_BYTE: return sizeof(GLubyte);
+ default: UNREACHABLE(); return sizeof(GLushort);
+ }
+}
+
+IndexBuffer::IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format) : mDevice(device), mBufferSize(size), mIndexBuffer(NULL)
+{
+ if (size > 0)
+ {
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
+ HRESULT result = device->CreateIndexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, format, pool, &mIndexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating an index buffer of size %lu.", size);
+ }
+ }
+}
+
+IndexBuffer::~IndexBuffer()
+{
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Release();
+ }
+}
+
+IDirect3DIndexBuffer9 *IndexBuffer::getBuffer() const
+{
+ return mIndexBuffer;
+}
+
+void IndexBuffer::unmap()
+{
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Unlock();
+ }
+}
+
+StreamingIndexBuffer::StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format) : IndexBuffer(device, initialSize, format)
+{
+ mWritePosition = 0;
+}
+
+StreamingIndexBuffer::~StreamingIndexBuffer()
+{
+}
+
+void *StreamingIndexBuffer::map(UINT requiredSpace, UINT *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mIndexBuffer)
+ {
+ HRESULT result = mIndexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
+
+ if (FAILED(result))
+ {
+ ERR(" Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StreamingIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
+{
+ if (requiredSpace > mBufferSize)
+ {
+ if (mIndexBuffer)
+ {
+ mIndexBuffer->Release();
+ mIndexBuffer = NULL;
+ }
+
+ mBufferSize = std::max(requiredSpace, 2 * mBufferSize);
+
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
+ HRESULT result = mDevice->CreateIndexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+ else if (mWritePosition + requiredSpace > mBufferSize) // Recycle
+ {
+ void *dummy;
+ mIndexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ mIndexBuffer->Unlock();
+
+ mWritePosition = 0;
+ }
+}
+
+StaticIndexBuffer::StaticIndexBuffer(IDirect3DDevice9 *device) : IndexBuffer(device, 0, D3DFMT_UNKNOWN)
+{
+ mCacheType = GL_NONE;
+}
+
+StaticIndexBuffer::~StaticIndexBuffer()
+{
+}
+
+void *StaticIndexBuffer::map(UINT requiredSpace, UINT *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mIndexBuffer)
+ {
+ HRESULT result = mIndexBuffer->Lock(0, requiredSpace, &mapPtr, 0);
+
+ if (FAILED(result))
+ {
+ ERR(" Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = 0;
+ }
+
+ return mapPtr;
+}
+
+void StaticIndexBuffer::reserveSpace(UINT requiredSpace, GLenum type)
+{
+ if (!mIndexBuffer && mBufferSize == 0)
+ {
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY);
+ HRESULT result = mDevice->CreateIndexBuffer(requiredSpace, D3DUSAGE_WRITEONLY, type == GL_UNSIGNED_INT ? D3DFMT_INDEX32 : D3DFMT_INDEX16, pool, &mIndexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mBufferSize = requiredSpace;
+ mCacheType = type;
+ }
+ else if (mIndexBuffer && mBufferSize >= requiredSpace && mCacheType == type)
+ {
+ // Already allocated
+ }
+ else UNREACHABLE(); // Static index buffers can't be resized
+}
+
+bool StaticIndexBuffer::lookupType(GLenum type)
+{
+ return mCacheType == type;
+}
+
+UINT StaticIndexBuffer::lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex)
+{
+ for (unsigned int range = 0; range < mCache.size(); range++)
+ {
+ if (mCache[range].offset == offset && mCache[range].count == count)
+ {
+ *minIndex = mCache[range].minIndex;
+ *maxIndex = mCache[range].maxIndex;
+
+ return mCache[range].streamOffset;
+ }
+ }
+
+ return -1;
+}
+
+void StaticIndexBuffer::addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset)
+{
+ IndexRange indexRange = {offset, count, minIndex, maxIndex, streamOffset};
+ mCache.push_back(indexRange);
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.h b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.h
new file mode 100644
index 000000000..d48249c79
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/IndexDataManager.h
@@ -0,0 +1,120 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// geometry/IndexDataManager.h: Defines the IndexDataManager, a class that
+// runs the Buffer translation process for index buffers.
+
+#ifndef LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
+#define LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
+
+#include <vector>
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "libGLESv2/Context.h"
+
+namespace gl
+{
+
+struct TranslatedIndexData
+{
+ UINT minIndex;
+ UINT maxIndex;
+ UINT startIndex;
+
+ IDirect3DIndexBuffer9 *indexBuffer;
+};
+
+class IndexBuffer
+{
+ public:
+ IndexBuffer(IDirect3DDevice9 *device, UINT size, D3DFORMAT format);
+ virtual ~IndexBuffer();
+
+ UINT size() const { return mBufferSize; }
+ virtual void *map(UINT requiredSpace, UINT *offset) = 0;
+ void unmap();
+ virtual void reserveSpace(UINT requiredSpace, GLenum type) = 0;
+
+ IDirect3DIndexBuffer9 *getBuffer() const;
+
+ protected:
+ IDirect3DDevice9 *const mDevice;
+
+ IDirect3DIndexBuffer9 *mIndexBuffer;
+ UINT mBufferSize;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexBuffer);
+};
+
+class StreamingIndexBuffer : public IndexBuffer
+{
+ public:
+ StreamingIndexBuffer(IDirect3DDevice9 *device, UINT initialSize, D3DFORMAT format);
+ ~StreamingIndexBuffer();
+
+ void *map(UINT requiredSpace, UINT *offset);
+ void reserveSpace(UINT requiredSpace, GLenum type);
+
+ private:
+ UINT mWritePosition;
+};
+
+class StaticIndexBuffer : public IndexBuffer
+{
+ public:
+ explicit StaticIndexBuffer(IDirect3DDevice9 *device);
+ ~StaticIndexBuffer();
+
+ void *map(UINT requiredSpace, UINT *offset);
+ void reserveSpace(UINT requiredSpace, GLenum type);
+
+ bool lookupType(GLenum type);
+ UINT lookupRange(intptr_t offset, GLsizei count, UINT *minIndex, UINT *maxIndex); // Returns the offset into the index buffer, or -1 if not found
+ void addRange(intptr_t offset, GLsizei count, UINT minIndex, UINT maxIndex, UINT streamOffset);
+
+ private:
+ GLenum mCacheType;
+
+ struct IndexRange
+ {
+ intptr_t offset;
+ GLsizei count;
+
+ UINT minIndex;
+ UINT maxIndex;
+ UINT streamOffset;
+ };
+
+ std::vector<IndexRange> mCache;
+};
+
+class IndexDataManager
+{
+ public:
+ IndexDataManager(Context *context, IDirect3DDevice9 *evice);
+ virtual ~IndexDataManager();
+
+ GLenum prepareIndexData(GLenum type, GLsizei count, Buffer *arrayElementBuffer, const void *indices, TranslatedIndexData *translated);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IndexDataManager);
+
+ std::size_t typeSize(GLenum type) const;
+ std::size_t indexSize(D3DFORMAT format) const;
+
+ IDirect3DDevice9 *const mDevice;
+
+ StreamingIndexBuffer *mStreamingBufferShort;
+ StreamingIndexBuffer *mStreamingBufferInt;
+};
+
+}
+
+#endif // LIBGLESV2_GEOMETRY_INDEXDATAMANAGER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/VertexDataManager.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/VertexDataManager.cpp
new file mode 100644
index 000000000..99ece1775
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/VertexDataManager.cpp
@@ -0,0 +1,769 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// geometry/VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#include "libGLESv2/geometry/VertexDataManager.h"
+
+#include "common/debug.h"
+
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/main.h"
+
+#include "libGLESv2/geometry/vertexconversion.h"
+#include "libGLESv2/geometry/IndexDataManager.h"
+
+namespace
+{
+ enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
+}
+
+namespace gl
+{
+
+VertexDataManager::VertexDataManager(Context *context, IDirect3DDevice9 *device) : mContext(context), mDevice(device)
+{
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDirtyCurrentValue[i] = true;
+ mCurrentValueBuffer[i] = NULL;
+ }
+
+ const D3DCAPS9 &caps = context->getDeviceCaps();
+ checkVertexCaps(caps.DeclTypes);
+
+ mStreamingBuffer = new StreamingVertexBuffer(mDevice, INITIAL_STREAM_BUFFER_SIZE);
+}
+
+VertexDataManager::~VertexDataManager()
+{
+ delete mStreamingBuffer;
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ delete mCurrentValueBuffer[i];
+ }
+}
+
+UINT VertexDataManager::writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute)
+{
+ Buffer *buffer = attribute.mBoundBuffer.get();
+
+ int inputStride = attribute.stride();
+ int elementSize = attribute.typeSize();
+ const FormatConverter &converter = formatConverter(attribute);
+ UINT streamOffset = 0;
+
+ void *output = NULL;
+
+ if (vertexBuffer)
+ {
+ output = vertexBuffer->map(attribute, spaceRequired(attribute, count), &streamOffset);
+ }
+
+ if (output == NULL)
+ {
+ ERR("Failed to map vertex buffer.");
+ return -1;
+ }
+
+ const char *input = NULL;
+
+ if (buffer)
+ {
+ int offset = attribute.mOffset;
+
+ input = static_cast<const char*>(buffer->data()) + offset;
+ }
+ else
+ {
+ input = static_cast<const char*>(attribute.mPointer);
+ }
+
+ input += inputStride * start;
+
+ if (converter.identity && inputStride == elementSize)
+ {
+ memcpy(output, input, count * inputStride);
+ }
+ else
+ {
+ converter.convertArray(input, inputStride, count, output);
+ }
+
+ vertexBuffer->unmap();
+
+ return streamOffset;
+}
+
+GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *translated)
+{
+ GLenum error = GL_NO_ERROR;
+ const VertexAttributeArray &attribs = mContext->getVertexAttributes();
+ Program *program = mContext->getCurrentProgram();
+
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ translated[attributeIndex].active = (program->getSemanticIndex(attributeIndex) != -1);
+ }
+
+ // Determine the required storage size per used buffer
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (translated[i].active && attribs[i].mArrayEnabled && (buffer || attribs[i].mPointer))
+ {
+ StaticVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
+
+ if (staticBuffer && staticBuffer->size() == 0)
+ {
+ int totalCount = buffer->size() / attribs[i].stride();
+ staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount));
+ }
+ else if (!staticBuffer || staticBuffer->lookupAttribute(attribs[i]) == -1)
+ {
+ if (mStreamingBuffer)
+ {
+ mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count));
+ }
+ }
+ }
+ }
+
+ // Invalidate static buffers if the attribute formats no longer match
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (translated[i].active && attribs[i].mArrayEnabled && buffer)
+ {
+ StaticVertexBuffer *staticBuffer = buffer->getVertexBuffer();
+
+ if (staticBuffer && staticBuffer->size() != 0)
+ {
+ bool matchingAttributes = true;
+
+ for (int j = 0; j < MAX_VERTEX_ATTRIBS; j++)
+ {
+ if (translated[j].active && attribs[j].mArrayEnabled && attribs[j].mBoundBuffer.get() == buffer)
+ {
+ if (staticBuffer->lookupAttribute(attribs[j]) == -1)
+ {
+ matchingAttributes = false;
+ break;
+ }
+ }
+ }
+
+ if (!matchingAttributes && mStreamingBuffer)
+ {
+ mStreamingBuffer->addRequiredSpaceFor(staticBuffer);
+ buffer->invalidateStaticData();
+ }
+ }
+ }
+ }
+
+ // Reserve the required space per used buffer
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (translated[i].active && attribs[i].mArrayEnabled && (buffer || attribs[i].mPointer))
+ {
+ ArrayVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
+ ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : mStreamingBuffer;
+
+ if (vertexBuffer)
+ {
+ vertexBuffer->reserveRequiredSpace();
+ }
+ }
+ }
+
+ // Perform the vertex data translations
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (translated[i].active)
+ {
+ Buffer *buffer = attribs[i].mBoundBuffer.get();
+
+ if (attribs[i].mArrayEnabled)
+ {
+ if (!buffer && attribs[i].mPointer == NULL)
+ {
+ // This is an application error that would normally result in a crash, but we catch it and return an error
+ ERR("An enabled vertex array has no buffer and no pointer.");
+ return GL_INVALID_OPERATION;
+ }
+
+ const FormatConverter &converter = formatConverter(attribs[i]);
+
+ StaticVertexBuffer *staticBuffer = buffer ? buffer->getVertexBuffer() : NULL;
+ ArrayVertexBuffer *vertexBuffer = staticBuffer ? staticBuffer : static_cast<ArrayVertexBuffer*>(mStreamingBuffer);
+
+ UINT streamOffset = -1;
+
+ if (staticBuffer)
+ {
+ streamOffset = staticBuffer->lookupAttribute(attribs[i]);
+
+ if (streamOffset == -1)
+ {
+ // Convert the entire buffer
+ int totalCount = buffer->size() / attribs[i].stride();
+ int startIndex = attribs[i].mOffset / attribs[i].stride();
+
+ streamOffset = writeAttributeData(staticBuffer, -startIndex, totalCount, attribs[i]);
+ }
+
+ if (streamOffset != -1)
+ {
+ streamOffset += (start + attribs[i].mOffset / attribs[i].stride()) * converter.outputElementSize;
+ }
+ }
+ else
+ {
+ streamOffset = writeAttributeData(mStreamingBuffer, start, count, attribs[i]);
+ }
+
+ if (streamOffset == -1)
+ {
+ return GL_OUT_OF_MEMORY;
+ }
+
+ translated[i].vertexBuffer = vertexBuffer->getBuffer();
+ translated[i].type = converter.d3dDeclType;
+ translated[i].stride = converter.outputElementSize;
+ translated[i].offset = streamOffset;
+ }
+ else
+ {
+ if (mDirtyCurrentValue[i])
+ {
+ delete mCurrentValueBuffer[i];
+ mCurrentValueBuffer[i] = new ConstantVertexBuffer(mDevice, attribs[i].mCurrentValue[0], attribs[i].mCurrentValue[1], attribs[i].mCurrentValue[2], attribs[i].mCurrentValue[3]);
+ mDirtyCurrentValue[i] = false;
+ }
+
+ translated[i].vertexBuffer = mCurrentValueBuffer[i]->getBuffer();
+
+ translated[i].type = D3DDECLTYPE_FLOAT4;
+ translated[i].stride = 0;
+ translated[i].offset = 0;
+ }
+ }
+ }
+
+ return GL_NO_ERROR;
+}
+
+std::size_t VertexDataManager::spaceRequired(const VertexAttribute &attrib, std::size_t count) const
+{
+ return formatConverter(attrib).outputElementSize * count;
+}
+
+// Mapping from OpenGL-ES vertex attrib type to D3D decl type:
+//
+// BYTE SHORT (Cast)
+// BYTE-norm FLOAT (Normalize) (can't be exactly represented as SHORT-norm)
+// UNSIGNED_BYTE UBYTE4 (Identity) or SHORT (Cast)
+// UNSIGNED_BYTE-norm UBYTE4N (Identity) or FLOAT (Normalize)
+// SHORT SHORT (Identity)
+// SHORT-norm SHORT-norm (Identity) or FLOAT (Normalize)
+// UNSIGNED_SHORT FLOAT (Cast)
+// UNSIGNED_SHORT-norm USHORT-norm (Identity) or FLOAT (Normalize)
+// FIXED (not in WebGL) FLOAT (FixedToFloat)
+// FLOAT FLOAT (Identity)
+
+// GLToCType maps from GL type (as GLenum) to the C typedef.
+template <GLenum GLType> struct GLToCType { };
+
+template <> struct GLToCType<GL_BYTE> { typedef GLbyte type; };
+template <> struct GLToCType<GL_UNSIGNED_BYTE> { typedef GLubyte type; };
+template <> struct GLToCType<GL_SHORT> { typedef GLshort type; };
+template <> struct GLToCType<GL_UNSIGNED_SHORT> { typedef GLushort type; };
+template <> struct GLToCType<GL_FIXED> { typedef GLuint type; };
+template <> struct GLToCType<GL_FLOAT> { typedef GLfloat type; };
+
+// This differs from D3DDECLTYPE in that it is unsized. (Size expansion is applied last.)
+enum D3DVertexType
+{
+ D3DVT_FLOAT,
+ D3DVT_SHORT,
+ D3DVT_SHORT_NORM,
+ D3DVT_UBYTE,
+ D3DVT_UBYTE_NORM,
+ D3DVT_USHORT_NORM
+};
+
+// D3DToCType maps from D3D vertex type (as enum D3DVertexType) to the corresponding C type.
+template <unsigned int D3DType> struct D3DToCType { };
+
+template <> struct D3DToCType<D3DVT_FLOAT> { typedef float type; };
+template <> struct D3DToCType<D3DVT_SHORT> { typedef short type; };
+template <> struct D3DToCType<D3DVT_SHORT_NORM> { typedef short type; };
+template <> struct D3DToCType<D3DVT_UBYTE> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_UBYTE_NORM> { typedef unsigned char type; };
+template <> struct D3DToCType<D3DVT_USHORT_NORM> { typedef unsigned short type; };
+
+// Encode the type/size combinations that D3D permits. For each type/size it expands to a widener that will provide the appropriate final size.
+template <unsigned int type, int size>
+struct WidenRule
+{
+};
+
+template <int size> struct WidenRule<D3DVT_FLOAT, size> : gl::NoWiden<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT, size> : gl::WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_SHORT_NORM, size> : gl::WidenToEven<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE, size> : gl::WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_UBYTE_NORM, size> : gl::WidenToFour<size> { };
+template <int size> struct WidenRule<D3DVT_USHORT_NORM, size> : gl::WidenToEven<size> { };
+
+// VertexTypeFlags encodes the D3DCAPS9::DeclType flag and vertex declaration flag for each D3D vertex type & size combination.
+template <unsigned int d3dtype, int size>
+struct VertexTypeFlags
+{
+};
+
+template <unsigned int capflag, unsigned int declflag>
+struct VertexTypeFlagsHelper
+{
+ enum { capflag = capflag };
+ enum { declflag = declflag };
+};
+
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 1> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT1> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT2> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 3> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT3> { };
+template <> struct VertexTypeFlags<D3DVT_FLOAT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_FLOAT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 2> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT2> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT, 4> : VertexTypeFlagsHelper<0, D3DDECLTYPE_SHORT4> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT2N, D3DDECLTYPE_SHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_SHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_SHORT4N, D3DDECLTYPE_SHORT4N> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4, D3DDECLTYPE_UBYTE4> { };
+template <> struct VertexTypeFlags<D3DVT_UBYTE_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_UBYTE4N, D3DDECLTYPE_UBYTE4N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 2> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT2N, D3DDECLTYPE_USHORT2N> { };
+template <> struct VertexTypeFlags<D3DVT_USHORT_NORM, 4> : VertexTypeFlagsHelper<D3DDTCAPS_USHORT4N, D3DDECLTYPE_USHORT4N> { };
+
+
+// VertexTypeMapping maps GL type & normalized flag to preferred and fallback D3D vertex types (as D3DVertexType enums).
+template <GLenum GLtype, bool normalized>
+struct VertexTypeMapping
+{
+};
+
+template <D3DVertexType Preferred, D3DVertexType Fallback = Preferred>
+struct VertexTypeMappingBase
+{
+ enum { preferred = Preferred };
+ enum { fallback = Fallback };
+};
+
+template <> struct VertexTypeMapping<GL_BYTE, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Cast
+template <> struct VertexTypeMapping<GL_BYTE, true> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, false> : VertexTypeMappingBase<D3DVT_UBYTE, D3DVT_FLOAT> { }; // Identity, Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_BYTE, true> : VertexTypeMappingBase<D3DVT_UBYTE_NORM, D3DVT_FLOAT> { }; // Identity, Normalize
+template <> struct VertexTypeMapping<GL_SHORT, false> : VertexTypeMappingBase<D3DVT_SHORT> { }; // Identity
+template <> struct VertexTypeMapping<GL_SHORT, true> : VertexTypeMappingBase<D3DVT_SHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, false> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Cast
+template <> struct VertexTypeMapping<GL_UNSIGNED_SHORT, true> : VertexTypeMappingBase<D3DVT_USHORT_NORM, D3DVT_FLOAT> { }; // Cast, Normalize
+template <bool normalized> struct VertexTypeMapping<GL_FIXED, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // FixedToFloat
+template <bool normalized> struct VertexTypeMapping<GL_FLOAT, normalized> : VertexTypeMappingBase<D3DVT_FLOAT> { }; // Identity
+
+
+// Given a GL type & norm flag and a D3D type, ConversionRule provides the type conversion rule (Cast, Normalize, Identity, FixedToFloat).
+// The conversion rules themselves are defined in vertexconversion.h.
+
+// Almost all cases are covered by Cast (including those that are actually Identity since Cast<T,T> knows it's an identity mapping).
+template <GLenum fromType, bool normalized, unsigned int toType>
+struct ConversionRule : gl::Cast<typename GLToCType<fromType>::type, typename D3DToCType<toType>::type>
+{
+};
+
+// All conversions from normalized types to float use the Normalize operator.
+template <GLenum fromType> struct ConversionRule<fromType, true, D3DVT_FLOAT> : gl::Normalize<typename GLToCType<fromType>::type> { };
+
+// Use a full specialisation for this so that it preferentially matches ahead of the generic normalize-to-float rules.
+template <> struct ConversionRule<GL_FIXED, true, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
+template <> struct ConversionRule<GL_FIXED, false, D3DVT_FLOAT> : gl::FixedToFloat<GLuint, 16> { };
+
+// A 2-stage construction is used for DefaultVertexValues because float must use SimpleDefaultValues (i.e. 0/1)
+// whether it is normalized or not.
+template <class T, bool normalized>
+struct DefaultVertexValuesStage2
+{
+};
+
+template <class T> struct DefaultVertexValuesStage2<T, true> : gl::NormalizedDefaultValues<T> { };
+template <class T> struct DefaultVertexValuesStage2<T, false> : gl::SimpleDefaultValues<T> { };
+
+// Work out the default value rule for a D3D type (expressed as the C type) and
+template <class T, bool normalized>
+struct DefaultVertexValues : DefaultVertexValuesStage2<T, normalized>
+{
+};
+
+template <bool normalized> struct DefaultVertexValues<float, normalized> : gl::SimpleDefaultValues<float> { };
+
+// Policy rules for use with Converter, to choose whether to use the preferred or fallback conversion.
+// The fallback conversion produces an output that all D3D9 devices must support.
+template <class T> struct UsePreferred { enum { type = T::preferred }; };
+template <class T> struct UseFallback { enum { type = T::fallback }; };
+
+// Converter ties it all together. Given an OpenGL type/norm/size and choice of preferred/fallback conversion,
+// it provides all the members of the appropriate VertexDataConverter, the D3DCAPS9::DeclTypes flag in cap flag
+// and the D3DDECLTYPE member needed for the vertex declaration in declflag.
+template <GLenum fromType, bool normalized, int size, template <class T> class PreferenceRule>
+struct Converter
+ : gl::VertexDataConverter<typename GLToCType<fromType>::type,
+ WidenRule<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type, size>,
+ ConversionRule<fromType,
+ normalized,
+ PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>,
+ DefaultVertexValues<typename D3DToCType<PreferenceRule< VertexTypeMapping<fromType, normalized> >::type>::type, normalized > >
+{
+private:
+ enum { d3dtype = PreferenceRule< VertexTypeMapping<fromType, normalized> >::type };
+ enum { d3dsize = WidenRule<d3dtype, size>::finalWidth };
+
+public:
+ enum { capflag = VertexTypeFlags<d3dtype, d3dsize>::capflag };
+ enum { declflag = VertexTypeFlags<d3dtype, d3dsize>::declflag };
+};
+
+// Initialise a TranslationInfo
+#define TRANSLATION(type, norm, size, preferred) \
+ { \
+ Converter<type, norm, size, preferred>::identity, \
+ Converter<type, norm, size, preferred>::finalSize, \
+ Converter<type, norm, size, preferred>::convertArray, \
+ static_cast<D3DDECLTYPE>(Converter<type, norm, size, preferred>::declflag) \
+ }
+
+#define TRANSLATION_FOR_TYPE_NORM_SIZE(type, norm, size) \
+ { \
+ Converter<type, norm, size, UsePreferred>::capflag, \
+ TRANSLATION(type, norm, size, UsePreferred), \
+ TRANSLATION(type, norm, size, UseFallback) \
+ }
+
+#define TRANSLATIONS_FOR_TYPE(type) \
+ { \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, false, 4) }, \
+ { TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 1), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 2), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 3), TRANSLATION_FOR_TYPE_NORM_SIZE(type, true, 4) }, \
+ }
+
+const VertexDataManager::TranslationDescription VertexDataManager::mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4] = // [GL types as enumerated by typeIndex()][normalized][size-1]
+{
+ TRANSLATIONS_FOR_TYPE(GL_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_BYTE),
+ TRANSLATIONS_FOR_TYPE(GL_SHORT),
+ TRANSLATIONS_FOR_TYPE(GL_UNSIGNED_SHORT),
+ TRANSLATIONS_FOR_TYPE(GL_FIXED),
+ TRANSLATIONS_FOR_TYPE(GL_FLOAT)
+};
+
+void VertexDataManager::checkVertexCaps(DWORD declTypes)
+{
+ for (unsigned int i = 0; i < NUM_GL_VERTEX_ATTRIB_TYPES; i++)
+ {
+ for (unsigned int j = 0; j < 2; j++)
+ {
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ if (mPossibleTranslations[i][j][k].capsFlag == 0 || (declTypes & mPossibleTranslations[i][j][k].capsFlag) != 0)
+ {
+ mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].preferredConversion;
+ }
+ else
+ {
+ mAttributeTypes[i][j][k] = mPossibleTranslations[i][j][k].fallbackConversion;
+ }
+ }
+ }
+ }
+}
+
+// This is used to index mAttributeTypes and mPossibleTranslations.
+unsigned int VertexDataManager::typeIndex(GLenum type) const
+{
+ switch (type)
+ {
+ case GL_BYTE: return 0;
+ case GL_UNSIGNED_BYTE: return 1;
+ case GL_SHORT: return 2;
+ case GL_UNSIGNED_SHORT: return 3;
+ case GL_FIXED: return 4;
+ case GL_FLOAT: return 5;
+
+ default: UNREACHABLE(); return 5;
+ }
+}
+
+void VertexDataManager::setupAttributes(const TranslatedAttribute *attributes)
+{
+ D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS];
+ D3DVERTEXELEMENT9 *element = &elements[0];
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (attributes[i].active)
+ {
+ mDevice->SetStreamSource(i, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride);
+
+ element->Stream = i;
+ element->Offset = 0;
+ element->Type = attributes[i].type;
+ element->Method = D3DDECLMETHOD_DEFAULT;
+ element->Usage = D3DDECLUSAGE_TEXCOORD;
+ element->UsageIndex = attributes[i].semanticIndex;
+ element++;
+ }
+ }
+
+ static const D3DVERTEXELEMENT9 end = D3DDECL_END();
+ *element = end;
+
+ IDirect3DVertexDeclaration9 *vertexDeclaration;
+ mDevice->CreateVertexDeclaration(elements, &vertexDeclaration);
+ mDevice->SetVertexDeclaration(vertexDeclaration);
+ vertexDeclaration->Release();
+}
+
+VertexBuffer::VertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : mDevice(device), mVertexBuffer(NULL)
+{
+ if (size > 0)
+ {
+ D3DPOOL pool = getDisplay()->getBufferPool(usageFlags);
+ HRESULT result = device->CreateVertexBuffer(size, usageFlags, 0, pool, &mVertexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", size);
+ }
+ }
+}
+
+VertexBuffer::~VertexBuffer()
+{
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Release();
+ }
+}
+
+void VertexBuffer::unmap()
+{
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Unlock();
+ }
+}
+
+IDirect3DVertexBuffer9 *VertexBuffer::getBuffer() const
+{
+ return mVertexBuffer;
+}
+
+ConstantVertexBuffer::ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w) : VertexBuffer(device, 4 * sizeof(float), D3DUSAGE_WRITEONLY)
+{
+ void *buffer = NULL;
+
+ if (mVertexBuffer)
+ {
+ HRESULT result = mVertexBuffer->Lock(0, 0, &buffer, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ }
+ }
+
+ if (buffer)
+ {
+ float *vector = (float*)buffer;
+
+ vector[0] = x;
+ vector[1] = y;
+ vector[2] = z;
+ vector[3] = w;
+
+ mVertexBuffer->Unlock();
+ }
+}
+
+ConstantVertexBuffer::~ConstantVertexBuffer()
+{
+}
+
+ArrayVertexBuffer::ArrayVertexBuffer(IDirect3DDevice9 *device, std::size_t size, DWORD usageFlags) : VertexBuffer(device, size, usageFlags)
+{
+ mBufferSize = size;
+ mWritePosition = 0;
+ mRequiredSpace = 0;
+}
+
+ArrayVertexBuffer::~ArrayVertexBuffer()
+{
+}
+
+void ArrayVertexBuffer::addRequiredSpace(UINT requiredSpace)
+{
+ mRequiredSpace += requiredSpace;
+}
+
+void ArrayVertexBuffer::addRequiredSpaceFor(ArrayVertexBuffer *buffer)
+{
+ mRequiredSpace += buffer->mRequiredSpace;
+}
+
+StreamingVertexBuffer::StreamingVertexBuffer(IDirect3DDevice9 *device, std::size_t initialSize) : ArrayVertexBuffer(device, initialSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY)
+{
+}
+
+StreamingVertexBuffer::~StreamingVertexBuffer()
+{
+}
+
+void *StreamingVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, std::size_t *offset)
+{
+ void *mapPtr = NULL;
+
+ if (mVertexBuffer)
+ {
+ HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, D3DLOCK_NOOVERWRITE);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ *offset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StreamingVertexBuffer::reserveRequiredSpace()
+{
+ if (mRequiredSpace > mBufferSize)
+ {
+ if (mVertexBuffer)
+ {
+ mVertexBuffer->Release();
+ mVertexBuffer = NULL;
+ }
+
+ mBufferSize = std::max(mRequiredSpace, 3 * mBufferSize / 2); // 1.5 x mBufferSize is arbitrary and should be checked to see we don't have too many reallocations.
+
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY);
+ HRESULT result = mDevice->CreateVertexBuffer(mBufferSize, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mBufferSize);
+ }
+
+ mWritePosition = 0;
+ }
+ else if (mWritePosition + mRequiredSpace > mBufferSize) // Recycle
+ {
+ if (mVertexBuffer)
+ {
+ void *dummy;
+ mVertexBuffer->Lock(0, 1, &dummy, D3DLOCK_DISCARD);
+ mVertexBuffer->Unlock();
+ }
+
+ mWritePosition = 0;
+ }
+
+ mRequiredSpace = 0;
+}
+
+StaticVertexBuffer::StaticVertexBuffer(IDirect3DDevice9 *device) : ArrayVertexBuffer(device, 0, D3DUSAGE_WRITEONLY)
+{
+}
+
+StaticVertexBuffer::~StaticVertexBuffer()
+{
+}
+
+void *StaticVertexBuffer::map(const VertexAttribute &attribute, std::size_t requiredSpace, UINT *streamOffset)
+{
+ void *mapPtr = NULL;
+
+ if (mVertexBuffer)
+ {
+ HRESULT result = mVertexBuffer->Lock(mWritePosition, requiredSpace, &mapPtr, 0);
+
+ if (FAILED(result))
+ {
+ ERR("Lock failed with error 0x%08x", result);
+ return NULL;
+ }
+
+ int attributeOffset = attribute.mOffset % attribute.stride();
+ VertexElement element = {attribute.mType, attribute.mSize, attribute.mNormalized, attributeOffset, mWritePosition};
+ mCache.push_back(element);
+
+ *streamOffset = mWritePosition;
+ mWritePosition += requiredSpace;
+ }
+
+ return mapPtr;
+}
+
+void StaticVertexBuffer::reserveRequiredSpace()
+{
+ if (!mVertexBuffer && mBufferSize == 0)
+ {
+ D3DPOOL pool = getDisplay()->getBufferPool(D3DUSAGE_WRITEONLY);
+ HRESULT result = mDevice->CreateVertexBuffer(mRequiredSpace, D3DUSAGE_WRITEONLY, 0, pool, &mVertexBuffer, NULL);
+
+ if (FAILED(result))
+ {
+ ERR("Out of memory allocating a vertex buffer of size %lu.", mRequiredSpace);
+ }
+
+ mBufferSize = mRequiredSpace;
+ }
+ else if (mVertexBuffer && mBufferSize >= mRequiredSpace)
+ {
+ // Already allocated
+ }
+ else UNREACHABLE(); // Static vertex buffers can't be resized
+
+ mRequiredSpace = 0;
+}
+
+UINT StaticVertexBuffer::lookupAttribute(const VertexAttribute &attribute)
+{
+ for (unsigned int element = 0; element < mCache.size(); element++)
+ {
+ if (mCache[element].type == attribute.mType && mCache[element].size == attribute.mSize && mCache[element].normalized == attribute.mNormalized)
+ {
+ if (mCache[element].attributeOffset == attribute.mOffset % attribute.stride())
+ {
+ return mCache[element].streamOffset;
+ }
+ }
+ }
+
+ return -1;
+}
+
+const VertexDataManager::FormatConverter &VertexDataManager::formatConverter(const VertexAttribute &attribute) const
+{
+ return mAttributeTypes[typeIndex(attribute.mType)][attribute.mNormalized][attribute.mSize - 1];
+}
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/VertexDataManager.h b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/VertexDataManager.h
new file mode 100644
index 000000000..257f2c309
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/VertexDataManager.h
@@ -0,0 +1,170 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// geometry/VertexDataManager.h: Defines the VertexDataManager, a class that
+// runs the Buffer translation process.
+
+#ifndef LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_
+#define LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_
+
+#include <vector>
+#include <cstddef>
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+
+#include "libGLESv2/Context.h"
+
+namespace gl
+{
+
+struct TranslatedAttribute
+{
+ bool active;
+
+ D3DDECLTYPE type;
+ UINT offset;
+ UINT stride; // 0 means not to advance the read pointer at all
+ UINT semanticIndex;
+
+ IDirect3DVertexBuffer9 *vertexBuffer;
+};
+
+class VertexBuffer
+{
+ public:
+ VertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
+ virtual ~VertexBuffer();
+
+ void unmap();
+
+ IDirect3DVertexBuffer9 *getBuffer() const;
+
+ protected:
+ IDirect3DDevice9 *const mDevice;
+ IDirect3DVertexBuffer9 *mVertexBuffer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexBuffer);
+};
+
+class ConstantVertexBuffer : public VertexBuffer
+{
+ public:
+ ConstantVertexBuffer(IDirect3DDevice9 *device, float x, float y, float z, float w);
+ ~ConstantVertexBuffer();
+};
+
+class ArrayVertexBuffer : public VertexBuffer
+{
+ public:
+ ArrayVertexBuffer(IDirect3DDevice9 *device, UINT size, DWORD usageFlags);
+ ~ArrayVertexBuffer();
+
+ UINT size() const { return mBufferSize; }
+ virtual void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset) = 0;
+ virtual void reserveRequiredSpace() = 0;
+ void addRequiredSpace(UINT requiredSpace);
+ void addRequiredSpaceFor(ArrayVertexBuffer *buffer);
+
+ protected:
+ UINT mBufferSize;
+ UINT mWritePosition;
+ UINT mRequiredSpace;
+};
+
+class StreamingVertexBuffer : public ArrayVertexBuffer
+{
+ public:
+ StreamingVertexBuffer(IDirect3DDevice9 *device, UINT initialSize);
+ ~StreamingVertexBuffer();
+
+ void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
+ void reserveRequiredSpace();
+};
+
+class StaticVertexBuffer : public ArrayVertexBuffer
+{
+ public:
+ explicit StaticVertexBuffer(IDirect3DDevice9 *device);
+ ~StaticVertexBuffer();
+
+ void *map(const VertexAttribute &attribute, UINT requiredSpace, UINT *streamOffset);
+ void reserveRequiredSpace();
+
+ UINT lookupAttribute(const VertexAttribute &attribute); // Returns the offset into the vertex buffer, or -1 if not found
+
+ private:
+ struct VertexElement
+ {
+ GLenum type;
+ GLint size;
+ bool normalized;
+ int attributeOffset;
+
+ UINT streamOffset;
+ };
+
+ std::vector<VertexElement> mCache;
+};
+
+class VertexDataManager
+{
+ public:
+ VertexDataManager(Context *context, IDirect3DDevice9 *backend);
+ virtual ~VertexDataManager();
+
+ void dirtyCurrentValue(int index) { mDirtyCurrentValue[index] = true; }
+
+ void setupAttributes(const TranslatedAttribute *attributes);
+ GLenum prepareVertexData(GLint start, GLsizei count, TranslatedAttribute *outAttribs);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VertexDataManager);
+
+ UINT spaceRequired(const VertexAttribute &attrib, std::size_t count) const;
+ UINT writeAttributeData(ArrayVertexBuffer *vertexBuffer, GLint start, GLsizei count, const VertexAttribute &attribute);
+
+ Context *const mContext;
+ IDirect3DDevice9 *const mDevice;
+
+ StreamingVertexBuffer *mStreamingBuffer;
+
+ bool mDirtyCurrentValue[MAX_VERTEX_ATTRIBS];
+ ConstantVertexBuffer *mCurrentValueBuffer[MAX_VERTEX_ATTRIBS];
+
+ // Attribute format conversion
+ struct FormatConverter
+ {
+ bool identity;
+ std::size_t outputElementSize;
+ void (*convertArray)(const void *in, std::size_t stride, std::size_t n, void *out);
+ D3DDECLTYPE d3dDeclType;
+ };
+
+ enum { NUM_GL_VERTEX_ATTRIB_TYPES = 6 };
+
+ FormatConverter mAttributeTypes[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
+
+ struct TranslationDescription
+ {
+ DWORD capsFlag;
+ FormatConverter preferredConversion;
+ FormatConverter fallbackConversion;
+ };
+
+ // This table is used to generate mAttributeTypes.
+ static const TranslationDescription mPossibleTranslations[NUM_GL_VERTEX_ATTRIB_TYPES][2][4]; // [GL types as enumerated by typeIndex()][normalized][size - 1]
+
+ void checkVertexCaps(DWORD declTypes);
+
+ unsigned int typeIndex(GLenum type) const;
+ const FormatConverter &formatConverter(const VertexAttribute &attribute) const;
+};
+
+}
+
+#endif // LIBGLESV2_GEOMETRY_VERTEXDATAMANAGER_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/vertexconversion.h b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/vertexconversion.h
new file mode 100644
index 000000000..e55dc72ce
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/geometry/vertexconversion.h
@@ -0,0 +1,208 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// geometry/vertexconversion.h: A library of vertex conversion classes that can be used to build
+// the FormatConverter objects used by the buffer conversion system.
+
+#ifndef LIBGLESV2_GEOMETRY_VERTEXCONVERSION_H_
+#define LIBGLESV2_GEOMETRY_VERTEXCONVERSION_H_
+
+#include <cstddef>
+#include <limits>
+
+#include "libGLESv2/Context.h" // Defines Index
+
+namespace gl
+{
+
+// Conversion types:
+// static const bool identity: true if this is an identity transform, false otherwise
+// static U convert(T): convert a single element from the input type to the output type
+// typedef ... OutputType: the type produced by this conversion
+
+template <class T>
+struct Identity
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return x;
+ }
+};
+
+template <class FromT, class ToT>
+struct Cast
+{
+ static const bool identity = false;
+
+ typedef ToT OutputType;
+
+ static ToT convert(FromT x)
+ {
+ return static_cast<ToT>(x);
+ }
+};
+
+template <class T>
+struct Cast<T, T>
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return static_cast<T>(x);
+ }
+};
+
+template <class T>
+struct Normalize
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(T x)
+ {
+ typedef std::numeric_limits<T> NL;
+ float f = static_cast<float>(x);
+
+ if (NL::is_signed)
+ {
+ // const float => VC2008 computes it at compile time
+ // static const float => VC2008 computes it the first time we get here, stores it to memory with static guard and all that.
+ const float divisor = 1.0f/(2*static_cast<float>(NL::max())+1);
+ return (2*f+1)*divisor;
+ }
+ else
+ {
+ return f/NL::max();
+ }
+ }
+};
+
+template <class FromType, std::size_t ScaleBits>
+struct FixedToFloat
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(FromType x)
+ {
+ const float divisor = 1.0f / static_cast<float>(static_cast<FromType>(1) << ScaleBits);
+ return static_cast<float>(x) * divisor;
+ }
+};
+
+// Widen types:
+// static const unsigned int initialWidth: number of components before conversion
+// static const unsigned int finalWidth: number of components after conversion
+
+// Float is supported at any size.
+template <std::size_t N>
+struct NoWiden
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N;
+};
+
+// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components
+template <std::size_t N>
+struct WidenToEven
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N+(N&1);
+};
+
+template <std::size_t N>
+struct WidenToFour
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = 4;
+};
+
+// Most types have 0 and 1 that are just that.
+template <class T>
+struct SimpleDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return static_cast<T>(1); }
+};
+
+// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value.
+template <class T>
+struct NormalizedDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return std::numeric_limits<T>::max(); }
+};
+
+// Converter:
+// static const bool identity: true if this is an identity transform (with no widening)
+// static const std::size_t finalSize: number of bytes per output vertex
+// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided.
+
+template <class InT, class WidenRule, class Converter, class DefaultValueRule = SimpleDefaultValues<InT> >
+struct VertexDataConverter
+{
+ typedef typename Converter::OutputType OutputType;
+ typedef InT InputType;
+
+ static const bool identity = (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity;
+ static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType);
+
+ static void convertArray(const InputType *in, std::size_t stride, std::size_t n, OutputType *out)
+ {
+ for (std::size_t i = 0; i < n; i++)
+ {
+ const InputType *ein = pointerAddBytes(in, i * stride);
+
+ copyComponent(out, ein, 0, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 1, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 2, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 3, static_cast<OutputType>(DefaultValueRule::one()));
+
+ out += WidenRule::finalWidth;
+ }
+ }
+
+ static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out)
+ {
+ return convertArray(static_cast<const InputType*>(in), stride, n, static_cast<OutputType*>(out));
+ }
+
+ private:
+ // Advance the given pointer by a number of bytes (not pointed-to elements).
+ template <class T>
+ static T *pointerAddBytes(T *basePtr, std::size_t numBytes)
+ {
+ return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(basePtr) + numBytes);
+ }
+
+ static void copyComponent(OutputType *out, const InputType *in, std::size_t elementindex, OutputType defaultvalue)
+ {
+ if (WidenRule::finalWidth > elementindex)
+ {
+ if (WidenRule::initialWidth > elementindex)
+ {
+ out[elementindex] = Converter::convert(in[elementindex]);
+ }
+ else
+ {
+ out[elementindex] = defaultvalue;
+ }
+ }
+ }
+};
+
+}
+
+#endif // LIBGLESV2_GEOMETRY_VERTEXCONVERSION_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.cpp
new file mode 100644
index 000000000..23957fe6d
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.cpp
@@ -0,0 +1,5723 @@
+//
+// Copyright (c) 2002-2011 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions.
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <exception>
+#include <limits>
+
+#include "common/debug.h"
+#include "common/version.h"
+
+#include "libGLESv2/main.h"
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/utilities.h"
+#include "libGLESv2/Buffer.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/Fence.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/Renderbuffer.h"
+#include "libGLESv2/Shader.h"
+#include "libGLESv2/Texture.h"
+
+bool validImageSize(GLint level, GLsizei width, GLsizei height)
+{
+ if (level < 0 || width < 0 || height < 0)
+ {
+ return false;
+ }
+
+ if (gl::getContext() && gl::getContext()->supportsNonPower2Texture())
+ {
+ return true;
+ }
+
+ if (level == 0)
+ {
+ return true;
+ }
+
+ if (gl::isPow2(width) && gl::isPow2(height))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+extern "C"
+{
+
+void __stdcall glActiveTexture(GLenum texture)
+{
+ EVENT("(GLenum texture = 0x%X)", texture);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + context->getMaximumCombinedTextureImageUnits() - 1)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ context->setActiveSampler(texture - GL_TEXTURE0);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glAttachShader(GLuint program, GLuint shader)
+{
+ EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (!shaderObject)
+ {
+ if (context->getProgram(shader))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (!programObject->attachShader(shaderObject))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
+{
+ EVENT("(GLuint program = %d, GLuint index = %d, const GLchar* name = 0x%0.8p)", program, index, name);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (strncmp(name, "gl_", 3) == 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ programObject->bindAttributeLocation(index, name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindBuffer(GLenum target, GLuint buffer)
+{
+ EVENT("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER:
+ context->bindArrayBuffer(buffer);
+ return;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ context->bindElementArrayBuffer(buffer);
+ return;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+ EVENT("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer);
+
+ try
+ {
+ if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (target == GL_READ_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+ {
+ context->bindReadFramebuffer(framebuffer);
+ }
+
+ if (target == GL_DRAW_FRAMEBUFFER_ANGLE || target == GL_FRAMEBUFFER)
+ {
+ context->bindDrawFramebuffer(framebuffer);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+ EVENT("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer);
+
+ try
+ {
+ if (target != GL_RENDERBUFFER)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->bindRenderbuffer(renderbuffer);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBindTexture(GLenum target, GLuint texture)
+{
+ EVENT("(GLenum target = 0x%X, GLuint texture = %d)", target, texture);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Texture *textureObject = context->getTexture(texture);
+
+ if (textureObject && textureObject->getTarget() != target && texture != 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ context->bindTexture2D(texture);
+ return;
+ case GL_TEXTURE_CUBE_MAP:
+ context->bindTextureCubeMap(texture);
+ return;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context* context = gl::getContext();
+
+ if (context)
+ {
+ context->setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBlendEquation(GLenum mode)
+{
+ glBlendEquationSeparate(mode, mode);
+}
+
+void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
+{
+ EVENT("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha);
+
+ try
+ {
+ switch (modeRGB)
+ {
+ case GL_FUNC_ADD:
+ case GL_FUNC_SUBTRACT:
+ case GL_FUNC_REVERSE_SUBTRACT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (modeAlpha)
+ {
+ case GL_FUNC_ADD:
+ case GL_FUNC_SUBTRACT:
+ case GL_FUNC_REVERSE_SUBTRACT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setBlendEquation(modeRGB, modeAlpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBlendFunc(GLenum sfactor, GLenum dfactor)
+{
+ glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
+}
+
+void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+{
+ EVENT("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)",
+ srcRGB, dstRGB, srcAlpha, dstAlpha);
+
+ try
+ {
+ switch (srcRGB)
+ {
+ case GL_ZERO:
+ case GL_ONE:
+ case GL_SRC_COLOR:
+ case GL_ONE_MINUS_SRC_COLOR:
+ case GL_DST_COLOR:
+ case GL_ONE_MINUS_DST_COLOR:
+ case GL_SRC_ALPHA:
+ case GL_ONE_MINUS_SRC_ALPHA:
+ case GL_DST_ALPHA:
+ case GL_ONE_MINUS_DST_ALPHA:
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ case GL_SRC_ALPHA_SATURATE:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (dstRGB)
+ {
+ case GL_ZERO:
+ case GL_ONE:
+ case GL_SRC_COLOR:
+ case GL_ONE_MINUS_SRC_COLOR:
+ case GL_DST_COLOR:
+ case GL_ONE_MINUS_DST_COLOR:
+ case GL_SRC_ALPHA:
+ case GL_ONE_MINUS_SRC_ALPHA:
+ case GL_DST_ALPHA:
+ case GL_ONE_MINUS_DST_ALPHA:
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (srcAlpha)
+ {
+ case GL_ZERO:
+ case GL_ONE:
+ case GL_SRC_COLOR:
+ case GL_ONE_MINUS_SRC_COLOR:
+ case GL_DST_COLOR:
+ case GL_ONE_MINUS_DST_COLOR:
+ case GL_SRC_ALPHA:
+ case GL_ONE_MINUS_SRC_ALPHA:
+ case GL_DST_ALPHA:
+ case GL_ONE_MINUS_DST_ALPHA:
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ case GL_SRC_ALPHA_SATURATE:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (dstAlpha)
+ {
+ case GL_ZERO:
+ case GL_ONE:
+ case GL_SRC_COLOR:
+ case GL_ONE_MINUS_SRC_COLOR:
+ case GL_DST_COLOR:
+ case GL_ONE_MINUS_DST_COLOR:
+ case GL_SRC_ALPHA:
+ case GL_ONE_MINUS_SRC_ALPHA:
+ case GL_DST_ALPHA:
+ case GL_ONE_MINUS_DST_ALPHA:
+ case GL_CONSTANT_COLOR:
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ case GL_CONSTANT_ALPHA:
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ bool constantColorUsed = (srcRGB == GL_CONSTANT_COLOR || srcRGB == GL_ONE_MINUS_CONSTANT_COLOR ||
+ dstRGB == GL_CONSTANT_COLOR || dstRGB == GL_ONE_MINUS_CONSTANT_COLOR);
+
+ bool constantAlphaUsed = (srcRGB == GL_CONSTANT_ALPHA || srcRGB == GL_ONE_MINUS_CONSTANT_ALPHA ||
+ dstRGB == GL_CONSTANT_ALPHA || dstRGB == GL_ONE_MINUS_CONSTANT_ALPHA);
+
+ if (constantColorUsed && constantAlphaUsed)
+ {
+ ERR("Simultaneous use of GL_CONSTANT_ALPHA/GL_ONE_MINUS_CONSTANT_ALPHA and GL_CONSTANT_COLOR/GL_ONE_MINUS_CONSTANT_COLOR invalid under WebGL");
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
+{
+ EVENT("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p, GLenum usage = %d)",
+ target, size, data, usage);
+
+ try
+ {
+ if (size < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch (usage)
+ {
+ case GL_STREAM_DRAW:
+ case GL_STATIC_DRAW:
+ case GL_DYNAMIC_DRAW:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Buffer *buffer;
+
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER:
+ buffer = context->getArrayBuffer();
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ buffer = context->getElementArrayBuffer();
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (!buffer)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ buffer->bufferData(data, size, usage);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
+{
+ EVENT("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = 0x%0.8p)",
+ target, offset, size, data);
+
+ try
+ {
+ if (size < 0 || offset < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (data == NULL)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Buffer *buffer;
+
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER:
+ buffer = context->getArrayBuffer();
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ buffer = context->getElementArrayBuffer();
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (!buffer)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if ((size_t)size + offset > buffer->size())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ buffer->bufferSubData(data, size, offset);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLenum __stdcall glCheckFramebufferStatus(GLenum target)
+{
+ EVENT("(GLenum target = 0x%X)", target);
+
+ try
+ {
+ if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return error(GL_INVALID_ENUM, 0);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Framebuffer *framebuffer = NULL;
+ if (target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ framebuffer = context->getReadFramebuffer();
+ }
+ else
+ {
+ framebuffer = context->getDrawFramebuffer();
+ }
+
+ return framebuffer->completeness();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, 0);
+ }
+
+ return 0;
+}
+
+void __stdcall glClear(GLbitfield mask)
+{
+ EVENT("(GLbitfield mask = %X)", mask);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->clear(mask);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+ EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setClearColor(red, green, blue, alpha);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glClearDepthf(GLclampf depth)
+{
+ EVENT("(GLclampf depth = %f)", depth);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setClearDepth(depth);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glClearStencil(GLint s)
+{
+ EVENT("(GLint s = %d)", s);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setClearStencil(s);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+ EVENT("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)",
+ red, green, blue, alpha);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCompileShader(GLuint shader)
+{
+ EVENT("(GLuint shader = %d)", shader);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ if (context->getProgram(shader))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ shaderObject->compile();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
+ GLint border, GLsizei imageSize, const GLvoid* data)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
+ "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
+ target, level, internalformat, width, height, border, imageSize, data);
+
+ try
+ {
+ if (!validImageSize(level, width, height) || border != 0 || imageSize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch (internalformat)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (border != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ if (width > (context->getMaximumTextureDimension() >> level) ||
+ height > (context->getMaximumTextureDimension() >> level))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ if (width != height)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+ height > (context->getMaximumCubeTextureDimension() >> level))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (!context->supportsCompressedTextures())
+ {
+ return error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
+ }
+
+ if (imageSize != gl::ComputeCompressedSize(width, height, internalformat))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
+ }
+ else
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize, const GLvoid* data)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, "
+ "GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
+ target, level, xoffset, yoffset, width, height, format, imageSize, data);
+
+ try
+ {
+ if (!gl::IsTextureTarget(target))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch (format)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (width == 0 || height == 0 || data == NULL)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (!context->supportsCompressedTextures())
+ {
+ return error(GL_INVALID_ENUM); // in this case, it's as though the format switch has failed.
+ }
+
+ if (imageSize != gl::ComputeCompressedSize(width, height, format))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (xoffset % 4 != 0 || yoffset % 4 != 0)
+ {
+ return error(GL_INVALID_OPERATION); // we wait to check the offsets until this point, because the multiple-of-four restriction
+ // does not exist unless DXT1 textures are supported.
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!texture->isCompressed())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if ((width % 4 != 0 && width != texture->getWidth()) ||
+ (height % 4 != 0 && height != texture->getHeight()))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
+ }
+ else if (gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!texture->isCompressed())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if ((width % 4 != 0 && width != texture->getWidth()) ||
+ (height % 4 != 0 && height != texture->getHeight()))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
+ "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)",
+ target, level, internalformat, x, y, width, height, border);
+
+ try
+ {
+ if (!validImageSize(level, width, height))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (border != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ if (width > (context->getMaximumTextureDimension() >> level) ||
+ height > (context->getMaximumTextureDimension() >> level))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ if (width != height)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+ height > (context->getMaximumCubeTextureDimension() >> level))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Framebuffer *framebuffer = context->getReadFramebuffer();
+
+ if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if (context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() != 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Colorbuffer *source = framebuffer->getColorbuffer();
+ GLenum colorbufferFormat = source->getInternalFormat();
+
+ // [OpenGL ES 2.0.24] table 3.9
+ switch (internalformat)
+ {
+ case GL_ALPHA:
+ if (colorbufferFormat != GL_ALPHA &&
+ colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_LUMINANCE:
+ case GL_RGB:
+ if (colorbufferFormat != GL_RGB &&
+ colorbufferFormat != GL_RGB565 &&
+ colorbufferFormat != GL_RGB8_OES &&
+ colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ if (colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ if (context->supportsCompressedTextures())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->copyImage(level, internalformat, x, y, width, height, framebuffer);
+ }
+ else if (gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer);
+ }
+ else UNREACHABLE();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
+ target, level, xoffset, yoffset, x, y, width, height);
+
+ try
+ {
+ if (!gl::IsTextureTarget(target))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (width == 0 || height == 0)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Framebuffer *framebuffer = context->getReadFramebuffer();
+
+ if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
+ {
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
+ }
+
+ if (context->getReadFramebufferHandle() != 0 && framebuffer->getColorbuffer()->getSamples() != 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Colorbuffer *source = framebuffer->getColorbuffer();
+ GLenum colorbufferFormat = source->getInternalFormat();
+ gl::Texture *texture = NULL;
+
+ if (target == GL_TEXTURE_2D)
+ {
+ texture = context->getTexture2D();
+ }
+ else if (gl::IsCubemapTextureTarget(target))
+ {
+ texture = context->getTextureCubeMap();
+ }
+ else UNREACHABLE();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ GLenum textureFormat = texture->getInternalFormat();
+
+ // [OpenGL ES 2.0.24] table 3.9
+ switch (textureFormat)
+ {
+ case GL_ALPHA:
+ if (colorbufferFormat != GL_ALPHA &&
+ colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_LUMINANCE:
+ case GL_RGB:
+ if (colorbufferFormat != GL_RGB &&
+ colorbufferFormat != GL_RGB565 &&
+ colorbufferFormat != GL_RGB8_OES &&
+ colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGBA:
+ if (colorbufferFormat != GL_RGBA &&
+ colorbufferFormat != GL_RGBA4 &&
+ colorbufferFormat != GL_RGB5_A1 &&
+ colorbufferFormat != GL_RGBA8_OES)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ return error(GL_INVALID_OPERATION);
+ default:
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->copySubImage(target, level, xoffset, yoffset, x, y, width, height, framebuffer);
+ }
+ }
+
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLuint __stdcall glCreateProgram(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ return context->createProgram();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, 0);
+ }
+
+ return 0;
+}
+
+GLuint __stdcall glCreateShader(GLenum type)
+{
+ EVENT("(GLenum type = 0x%X)", type);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (type)
+ {
+ case GL_FRAGMENT_SHADER:
+ case GL_VERTEX_SHADER:
+ return context->createShader(type);
+ default:
+ return error(GL_INVALID_ENUM, 0);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, 0);
+ }
+
+ return 0;
+}
+
+void __stdcall glCullFace(GLenum mode)
+{
+ EVENT("(GLenum mode = 0x%X)", mode);
+
+ try
+ {
+ switch (mode)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setCullMode(mode);
+ }
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers)
+{
+ EVENT("(GLsizei n = %d, const GLuint* buffers = 0x%0.8p)", n, buffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ context->deleteBuffer(buffers[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteFencesNV(GLsizei n, const GLuint* fences)
+{
+ EVENT("(GLsizei n = %d, const GLuint* fences = 0x%0.8p)", n, fences);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ context->deleteFence(fences[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+{
+ EVENT("(GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p)", n, framebuffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ if (framebuffers[i] != 0)
+ {
+ context->deleteFramebuffer(framebuffers[i]);
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ if (program == 0)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (!context->getProgram(program))
+ {
+ if(context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ context->deleteProgram(program);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+{
+ EVENT("(GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ context->deleteRenderbuffer(renderbuffers[i]);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteShader(GLuint shader)
+{
+ EVENT("(GLuint shader = %d)", shader);
+
+ try
+ {
+ if (shader == 0)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (!context->getShader(shader))
+ {
+ if(context->getProgram(shader))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ context->deleteShader(shader);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures)
+{
+ EVENT("(GLsizei n = %d, const GLuint* textures = 0x%0.8p)", n, textures);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ if (textures[i] != 0)
+ {
+ context->deleteTexture(textures[i]);
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDepthFunc(GLenum func)
+{
+ EVENT("(GLenum func = 0x%X)", func);
+
+ try
+ {
+ switch (func)
+ {
+ case GL_NEVER:
+ case GL_ALWAYS:
+ case GL_LESS:
+ case GL_LEQUAL:
+ case GL_EQUAL:
+ case GL_GREATER:
+ case GL_GEQUAL:
+ case GL_NOTEQUAL:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setDepthFunc(func);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDepthMask(GLboolean flag)
+{
+ EVENT("(GLboolean flag = %d)", flag);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setDepthMask(flag != GL_FALSE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar)
+{
+ EVENT("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setDepthRange(zNear, zFar);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDetachShader(GLuint program, GLuint shader)
+{
+ EVENT("(GLuint program = %d, GLuint shader = %d)", program, shader);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+
+ gl::Program *programObject = context->getProgram(program);
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!programObject)
+ {
+ gl::Shader *shaderByProgramHandle;
+ shaderByProgramHandle = context->getShader(program);
+ if (!shaderByProgramHandle)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ else
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+
+ if (!shaderObject)
+ {
+ gl::Program *programByShaderHandle = context->getProgram(shader);
+ if (!programByShaderHandle)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ else
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+
+ if (!programObject->detachShader(shaderObject))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDisable(GLenum cap)
+{
+ EVENT("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (cap)
+ {
+ case GL_CULL_FACE: context->setCullFace(false); break;
+ case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(false); break;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(false); break;
+ case GL_SAMPLE_COVERAGE: context->setSampleCoverage(false); break;
+ case GL_SCISSOR_TEST: context->setScissorTest(false); break;
+ case GL_STENCIL_TEST: context->setStencilTest(false); break;
+ case GL_DEPTH_TEST: context->setDepthTest(false); break;
+ case GL_BLEND: context->setBlend(false); break;
+ case GL_DITHER: context->setDither(false); break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDisableVertexAttribArray(GLuint index)
+{
+ EVENT("(GLuint index = %d)", index);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setEnableVertexAttribArray(index, false);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count)
+{
+ EVENT("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count);
+
+ try
+ {
+ if (count < 0 || first < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->drawArrays(mode, first, count);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+{
+ EVENT("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = 0x%0.8p)",
+ mode, count, type, indices);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT:
+ break;
+ case GL_UNSIGNED_INT:
+ if (!context->supports32bitIndices())
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ context->drawElements(mode, count, type, indices);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glEnable(GLenum cap)
+{
+ EVENT("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (cap)
+ {
+ case GL_CULL_FACE: context->setCullFace(true); break;
+ case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFill(true); break;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverage(true); break;
+ case GL_SAMPLE_COVERAGE: context->setSampleCoverage(true); break;
+ case GL_SCISSOR_TEST: context->setScissorTest(true); break;
+ case GL_STENCIL_TEST: context->setStencilTest(true); break;
+ case GL_DEPTH_TEST: context->setDepthTest(true); break;
+ case GL_BLEND: context->setBlend(true); break;
+ case GL_DITHER: context->setDither(true); break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glEnableVertexAttribArray(GLuint index)
+{
+ EVENT("(GLuint index = %d)", index);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setEnableVertexAttribArray(index, true);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFinishFenceNV(GLuint fence)
+{
+ EVENT("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Fence* fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ fenceObject->finishFence();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFinish(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->finish();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFlush(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->flush();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+ EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, "
+ "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer);
+
+ try
+ {
+ if ((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ || renderbuffertarget != GL_RENDERBUFFER)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Framebuffer *framebuffer = NULL;
+ GLuint framebufferHandle = 0;
+ if (target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ framebuffer = context->getReadFramebuffer();
+ framebufferHandle = context->getReadFramebufferHandle();
+ }
+ else
+ {
+ framebuffer = context->getDrawFramebuffer();
+ framebufferHandle = context->getDrawFramebufferHandle();
+ }
+
+ if (framebufferHandle == 0 || !framebuffer)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (attachment)
+ {
+ case GL_COLOR_ATTACHMENT0:
+ framebuffer->setColorbuffer(GL_RENDERBUFFER, renderbuffer);
+ break;
+ case GL_DEPTH_ATTACHMENT:
+ framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer);
+ break;
+ case GL_STENCIL_ATTACHMENT:
+ framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer);
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+ EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "
+ "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level);
+
+ try
+ {
+ if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (attachment)
+ {
+ case GL_COLOR_ATTACHMENT0:
+ case GL_DEPTH_ATTACHMENT:
+ case GL_STENCIL_ATTACHMENT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (texture == 0)
+ {
+ textarget = GL_NONE;
+ }
+ else
+ {
+ gl::Texture *tex = context->getTexture(texture);
+
+ if (tex == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (tex->isCompressed())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (textarget)
+ {
+ case GL_TEXTURE_2D:
+ if (tex->getTarget() != GL_TEXTURE_2D)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (level != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ gl::Framebuffer *framebuffer = NULL;
+ GLuint framebufferHandle = 0;
+ if (target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ framebuffer = context->getReadFramebuffer();
+ framebufferHandle = context->getReadFramebufferHandle();
+ }
+ else
+ {
+ framebuffer = context->getDrawFramebuffer();
+ framebufferHandle = context->getDrawFramebufferHandle();
+ }
+
+ if (framebufferHandle == 0 || !framebuffer)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (attachment)
+ {
+ case GL_COLOR_ATTACHMENT0: framebuffer->setColorbuffer(textarget, texture); break;
+ case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture); break;
+ case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture); break;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glFrontFace(GLenum mode)
+{
+ EVENT("(GLenum mode = 0x%X)", mode);
+
+ try
+ {
+ switch (mode)
+ {
+ case GL_CW:
+ case GL_CCW:
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setFrontFace(mode);
+ }
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenBuffers(GLsizei n, GLuint* buffers)
+{
+ EVENT("(GLsizei n = %d, GLuint* buffers = 0x%0.8p)", n, buffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ buffers[i] = context->createBuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenerateMipmap(GLenum target)
+{
+ EVENT("(GLenum target = 0x%X)", target);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Texture *texture;
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (texture->isCompressed())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->generateMipmaps();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenFencesNV(GLsizei n, GLuint* fences)
+{
+ EVENT("(GLsizei n = %d, GLuint* fences = 0x%0.8p)", n, fences);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ fences[i] = context->createFence();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers)
+{
+ EVENT("(GLsizei n = %d, GLuint* framebuffers = 0x%0.8p)", n, framebuffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ framebuffers[i] = context->createFramebuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+{
+ EVENT("(GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p)", n, renderbuffers);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ renderbuffers[i] = context->createRenderbuffer();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGenTextures(GLsizei n, GLuint* textures)
+{
+ EVENT("(GLsizei n = %d, GLuint* textures = 0x%0.8p)", n, textures);
+
+ try
+ {
+ if (n < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ for (int i = 0; i < n; i++)
+ {
+ textures[i] = context->createTexture();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
+{
+ EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = 0x%0.8p, "
+ "GLint *size = 0x%0.8p, GLenum *type = %0.8p, GLchar *name = %0.8p)",
+ program, index, bufsize, length, size, type, name);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (index >= (GLuint)programObject->getActiveAttributeCount())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ programObject->getActiveAttribute(index, bufsize, length, size, type, name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
+{
+ EVENT("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, "
+ "GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, GLchar* name = 0x%0.8p)",
+ program, index, bufsize, length, size, type, name);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (index >= (GLuint)programObject->getActiveUniformCount())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ programObject->getActiveUniform(index, bufsize, length, size, type, name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+{
+ EVENT("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p)",
+ program, maxcount, count, shaders);
+
+ try
+ {
+ if (maxcount < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ return programObject->getAttachedShaders(maxcount, count, shaders);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+int __stdcall glGetAttribLocation(GLuint program, const GLchar* name)
+{
+ EVENT("(GLuint program = %d, const GLchar* name = %s)", program, name);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION, -1);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE, -1);
+ }
+ }
+
+ if (!programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION, -1);
+ }
+
+ return programObject->getAttributeLocation(name);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, -1);
+ }
+
+ return -1;
+}
+
+void __stdcall glGetBooleanv(GLenum pname, GLboolean* params)
+{
+ EVENT("(GLenum pname = 0x%X, GLboolean* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (!(context->getBooleanv(pname, params)))
+ {
+ GLenum nativeType;
+ unsigned int numParams = 0;
+ if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
+ return error(GL_INVALID_ENUM);
+
+ if (numParams == 0)
+ return; // it is known that the pname is valid, but there are no parameters to return
+
+ if (nativeType == GL_FLOAT)
+ {
+ GLfloat *floatParams = NULL;
+ floatParams = new GLfloat[numParams];
+
+ context->getFloatv(pname, floatParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (floatParams[i] == 0.0f)
+ params[i] = GL_FALSE;
+ else
+ params[i] = GL_TRUE;
+ }
+
+ delete [] floatParams;
+ }
+ else if (nativeType == GL_INT)
+ {
+ GLint *intParams = NULL;
+ intParams = new GLint[numParams];
+
+ context->getIntegerv(pname, intParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (intParams[i] == 0)
+ params[i] = GL_FALSE;
+ else
+ params[i] = GL_TRUE;
+ }
+
+ delete [] intParams;
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Buffer *buffer;
+
+ switch (target)
+ {
+ case GL_ARRAY_BUFFER:
+ buffer = context->getArrayBuffer();
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ buffer = context->getElementArrayBuffer();
+ break;
+ default: return error(GL_INVALID_ENUM);
+ }
+
+ if (!buffer)
+ {
+ // A null buffer means that "0" is bound to the requested buffer target
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (pname)
+ {
+ case GL_BUFFER_USAGE:
+ *params = buffer->usage();
+ break;
+ case GL_BUFFER_SIZE:
+ *params = buffer->size();
+ break;
+ default: return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLenum __stdcall glGetError(void)
+{
+ EVENT("()");
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ return context->getError();
+ }
+
+ return GL_NO_ERROR;
+}
+
+void __stdcall glGetFenceivNV(GLuint fence, GLenum pname, GLint *params)
+{
+ EVENT("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = 0x%0.8p)", fence, pname, params);
+
+ try
+ {
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Fence *fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ fenceObject->getFenceiv(pname, params);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetFloatv(GLenum pname, GLfloat* params)
+{
+ EVENT("(GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (!(context->getFloatv(pname, params)))
+ {
+ GLenum nativeType;
+ unsigned int numParams = 0;
+ if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
+ return error(GL_INVALID_ENUM);
+
+ if (numParams == 0)
+ return; // it is known that the pname is valid, but that there are no parameters to return.
+
+ if (nativeType == GL_BOOL)
+ {
+ GLboolean *boolParams = NULL;
+ boolParams = new GLboolean[numParams];
+
+ context->getBooleanv(pname, boolParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (boolParams[i] == GL_FALSE)
+ params[i] = 0.0f;
+ else
+ params[i] = 1.0f;
+ }
+
+ delete [] boolParams;
+ }
+ else if (nativeType == GL_INT)
+ {
+ GLint *intParams = NULL;
+ intParams = new GLint[numParams];
+
+ context->getIntegerv(pname, intParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ params[i] = (GLfloat)intParams[i];
+ }
+
+ delete [] intParams;
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)",
+ target, attachment, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER_ANGLE && target != GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Framebuffer *framebuffer = NULL;
+ if (target == GL_READ_FRAMEBUFFER_ANGLE)
+ {
+ if(context->getReadFramebufferHandle() == 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ framebuffer = context->getReadFramebuffer();
+ }
+ else
+ {
+ if (context->getDrawFramebufferHandle() == 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ framebuffer = context->getDrawFramebuffer();
+ }
+
+ GLenum attachmentType;
+ GLuint attachmentHandle;
+ switch (attachment)
+ {
+ case GL_COLOR_ATTACHMENT0:
+ attachmentType = framebuffer->getColorbufferType();
+ attachmentHandle = framebuffer->getColorbufferHandle();
+ break;
+ case GL_DEPTH_ATTACHMENT:
+ attachmentType = framebuffer->getDepthbufferType();
+ attachmentHandle = framebuffer->getDepthbufferHandle();
+ break;
+ case GL_STENCIL_ATTACHMENT:
+ attachmentType = framebuffer->getStencilbufferType();
+ attachmentHandle = framebuffer->getStencilbufferHandle();
+ break;
+ default: return error(GL_INVALID_ENUM);
+ }
+
+ GLenum attachmentObjectType; // Type category
+ if (attachmentType == GL_NONE || attachmentType == GL_RENDERBUFFER)
+ {
+ attachmentObjectType = attachmentType;
+ }
+ else if (gl::IsTextureTarget(attachmentType))
+ {
+ attachmentObjectType = GL_TEXTURE;
+ }
+ else UNREACHABLE();
+
+ switch (pname)
+ {
+ case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ *params = attachmentObjectType;
+ break;
+ case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ if (attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE)
+ {
+ *params = attachmentHandle;
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+ if (attachmentObjectType == GL_TEXTURE)
+ {
+ *params = 0; // FramebufferTexture2D will not allow level to be set to anything else in GL ES 2.0
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+ if (attachmentObjectType == GL_TEXTURE)
+ {
+ if (gl::IsCubemapTextureTarget(attachmentType))
+ {
+ *params = attachmentType;
+ }
+ else
+ {
+ *params = 0;
+ }
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetIntegerv(GLenum pname, GLint* params)
+{
+ EVENT("(GLenum pname = 0x%X, GLint* params = 0x%0.8p)", pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (!(context->getIntegerv(pname, params)))
+ {
+ GLenum nativeType;
+ unsigned int numParams = 0;
+ if (!context->getQueryParameterInfo(pname, &nativeType, &numParams))
+ return error(GL_INVALID_ENUM);
+
+ if (numParams == 0)
+ return; // it is known that pname is valid, but there are no parameters to return
+
+ if (nativeType == GL_BOOL)
+ {
+ GLboolean *boolParams = NULL;
+ boolParams = new GLboolean[numParams];
+
+ context->getBooleanv(pname, boolParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (boolParams[i] == GL_FALSE)
+ params[i] = 0;
+ else
+ params[i] = 1;
+ }
+
+ delete [] boolParams;
+ }
+ else if (nativeType == GL_FLOAT)
+ {
+ GLfloat *floatParams = NULL;
+ floatParams = new GLfloat[numParams];
+
+ context->getFloatv(pname, floatParams);
+
+ for (unsigned int i = 0; i < numParams; ++i)
+ {
+ if (pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
+ {
+ params[i] = (GLint)(((GLfloat)(0xFFFFFFFF) * floatParams[i] - 1.0f) / 2.0f);
+ }
+ else
+ params[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
+ }
+
+ delete [] floatParams;
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params)
+{
+ EVENT("(GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", program, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch (pname)
+ {
+ case GL_DELETE_STATUS:
+ *params = programObject->isFlaggedForDeletion();
+ return;
+ case GL_LINK_STATUS:
+ *params = programObject->isLinked();
+ return;
+ case GL_VALIDATE_STATUS:
+ *params = programObject->isValidated();
+ return;
+ case GL_INFO_LOG_LENGTH:
+ *params = programObject->getInfoLogLength();
+ return;
+ case GL_ATTACHED_SHADERS:
+ *params = programObject->getAttachedShadersCount();
+ return;
+ case GL_ACTIVE_ATTRIBUTES:
+ *params = programObject->getActiveAttributeCount();
+ return;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = programObject->getActiveAttributeMaxLength();
+ return;
+ case GL_ACTIVE_UNIFORMS:
+ *params = programObject->getActiveUniformCount();
+ return;
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = programObject->getActiveUniformMaxLength();
+ return;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+ EVENT("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",
+ program, bufsize, length, infolog);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ programObject->getInfoLog(bufsize, length, infolog);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (target != GL_RENDERBUFFER)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (context->getRenderbufferHandle() == 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getRenderbufferHandle());
+
+ switch (pname)
+ {
+ case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break;
+ case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break;
+ case GL_RENDERBUFFER_INTERNAL_FORMAT: *params = renderbuffer->getInternalFormat(); break;
+ case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break;
+ case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break;
+ case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break;
+ case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break;
+ case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break;
+ case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break;
+ case GL_RENDERBUFFER_SAMPLES_ANGLE:
+ if (context->getMaxSupportedSamples() != 0)
+ {
+ *params = renderbuffer->getSamples();
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+ EVENT("(GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p)", shader, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch (pname)
+ {
+ case GL_SHADER_TYPE:
+ *params = shaderObject->getType();
+ return;
+ case GL_DELETE_STATUS:
+ *params = shaderObject->isFlaggedForDeletion();
+ return;
+ case GL_COMPILE_STATUS:
+ *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE;
+ return;
+ case GL_INFO_LOG_LENGTH:
+ *params = shaderObject->getInfoLogLength();
+ return;
+ case GL_SHADER_SOURCE_LENGTH:
+ *params = shaderObject->getSourceLength();
+ return;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
+{
+ EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* infolog = 0x%0.8p)",
+ shader, bufsize, length, infolog);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ shaderObject->getInfoLog(bufsize, length, infolog);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+ EVENT("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p)",
+ shadertype, precisiontype, range, precision);
+
+ try
+ {
+ switch (shadertype)
+ {
+ case GL_VERTEX_SHADER:
+ case GL_FRAGMENT_SHADER:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (precisiontype)
+ {
+ case GL_LOW_FLOAT:
+ case GL_MEDIUM_FLOAT:
+ case GL_HIGH_FLOAT:
+ // Assume IEEE 754 precision
+ range[0] = 127;
+ range[1] = 127;
+ *precision = 23;
+ break;
+ case GL_LOW_INT:
+ case GL_MEDIUM_INT:
+ case GL_HIGH_INT:
+ // Some (most) hardware only supports single-precision floating-point numbers,
+ // which can accurately represent integers up to +/-16777216
+ range[0] = 24;
+ range[1] = 24;
+ *precision = 0;
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
+{
+ EVENT("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLchar* source = 0x%0.8p)",
+ shader, bufsize, length, source);
+
+ try
+ {
+ if (bufsize < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ shaderObject->getSource(bufsize, length, source);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+const GLubyte* __stdcall glGetString(GLenum name)
+{
+ EVENT("(GLenum name = 0x%X)", name);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ switch (name)
+ {
+ case GL_VENDOR:
+ return (GLubyte*)"Google Inc.";
+ case GL_RENDERER:
+ return (GLubyte*)"ANGLE";
+ case GL_VERSION:
+ return (GLubyte*)"OpenGL ES 2.0 (ANGLE "VERSION_STRING")";
+ case GL_SHADING_LANGUAGE_VERSION:
+ return (GLubyte*)"OpenGL ES GLSL ES 1.00 (ANGLE "VERSION_STRING")";
+ case GL_EXTENSIONS:
+ return (GLubyte*)((context != NULL) ? context->getExtensionString() : "");
+ default:
+ return error(GL_INVALID_ENUM, (GLubyte*)NULL);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, (GLubyte*)NULL);
+ }
+
+ return NULL;
+}
+
+void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Texture *texture;
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (pname)
+ {
+ case GL_TEXTURE_MAG_FILTER:
+ *params = (GLfloat)texture->getMagFilter();
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ *params = (GLfloat)texture->getMinFilter();
+ break;
+ case GL_TEXTURE_WRAP_S:
+ *params = (GLfloat)texture->getWrapS();
+ break;
+ case GL_TEXTURE_WRAP_T:
+ *params = (GLfloat)texture->getWrapT();
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", target, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Texture *texture;
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (pname)
+ {
+ case GL_TEXTURE_MAG_FILTER:
+ *params = texture->getMagFilter();
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ *params = texture->getMinFilter();
+ break;
+ case GL_TEXTURE_WRAP_S:
+ *params = texture->getWrapS();
+ break;
+ case GL_TEXTURE_WRAP_T:
+ *params = texture->getWrapT();
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params)
+{
+ EVENT("(GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p)", program, location, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (program == 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject || !programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!programObject->getUniformfv(location, params))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params)
+{
+ EVENT("(GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p)", program, location, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (program == 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject || !programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!programObject)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!programObject->getUniformiv(location, params))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+int __stdcall glGetUniformLocation(GLuint program, const GLchar* name)
+{
+ EVENT("(GLuint program = %d, const GLchar* name = 0x%0.8p)", program, name);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (strstr(name, "gl_") == name)
+ {
+ return -1;
+ }
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION, -1);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE, -1);
+ }
+ }
+
+ if (!programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION, -1);
+ }
+
+ return programObject->getUniformLocation(name, false);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, -1);
+ }
+
+ return -1;
+}
+
+void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+{
+ EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p)", index, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
+
+ switch (pname)
+ {
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+ *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+ *params = (GLfloat)attribState.mSize;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+ *params = (GLfloat)attribState.mStride;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+ *params = (GLfloat)attribState.mType;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ *params = (GLfloat)(attribState.mNormalized ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ *params = (GLfloat)attribState.mBoundBuffer.id();
+ break;
+ case GL_CURRENT_VERTEX_ATTRIB:
+ for (int i = 0; i < 4; ++i)
+ {
+ params[i] = attribState.mCurrentValue[i];
+ }
+ break;
+ default: return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+{
+ EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p)", index, pname, params);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ const gl::VertexAttribute &attribState = context->getVertexAttribState(index);
+
+ switch (pname)
+ {
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+ *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+ *params = attribState.mSize;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+ *params = attribState.mStride;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+ *params = attribState.mType;
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ *params = attribState.mBoundBuffer.id();
+ break;
+ case GL_CURRENT_VERTEX_ATTRIB:
+ for (int i = 0; i < 4; ++i)
+ {
+ float currentValue = attribState.mCurrentValue[i];
+ params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f));
+ }
+ break;
+ default: return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
+{
+ EVENT("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = 0x%0.8p)", index, pname, pointer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ *pointer = const_cast<GLvoid*>(context->getVertexAttribPointer(index));
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glHint(GLenum target, GLenum mode)
+{
+ EVENT("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode);
+
+ try
+ {
+ switch (mode)
+ {
+ case GL_FASTEST:
+ case GL_NICEST:
+ case GL_DONT_CARE:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+ switch (target)
+ {
+ case GL_GENERATE_MIPMAP_HINT:
+ if (context) context->setGenerateMipmapHint(mode);
+ break;
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+ if (context) context->setFragmentShaderDerivativeHint(mode);
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLboolean __stdcall glIsBuffer(GLuint buffer)
+{
+ EVENT("(GLuint buffer = %d)", buffer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context && buffer)
+ {
+ gl::Buffer *bufferObject = context->getBuffer(buffer);
+
+ if (bufferObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsEnabled(GLenum cap)
+{
+ EVENT("(GLenum cap = 0x%X)", cap);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (cap)
+ {
+ case GL_CULL_FACE: return context->isCullFaceEnabled();
+ case GL_POLYGON_OFFSET_FILL: return context->isPolygonOffsetFillEnabled();
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->isSampleAlphaToCoverageEnabled();
+ case GL_SAMPLE_COVERAGE: return context->isSampleCoverageEnabled();
+ case GL_SCISSOR_TEST: return context->isScissorTestEnabled();
+ case GL_STENCIL_TEST: return context->isStencilTestEnabled();
+ case GL_DEPTH_TEST: return context->isDepthTestEnabled();
+ case GL_BLEND: return context->isBlendEnabled();
+ case GL_DITHER: return context->isDitherEnabled();
+ default:
+ return error(GL_INVALID_ENUM, false);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, false);
+ }
+
+ return false;
+}
+
+GLboolean __stdcall glIsFenceNV(GLuint fence)
+{
+ EVENT("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Fence *fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return GL_FALSE;
+ }
+
+ return fenceObject->isFence();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsFramebuffer(GLuint framebuffer)
+{
+ EVENT("(GLuint framebuffer = %d)", framebuffer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context && framebuffer)
+ {
+ gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer);
+
+ if (framebufferObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context && program)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (programObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer)
+{
+ EVENT("(GLuint renderbuffer = %d)", renderbuffer);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context && renderbuffer)
+ {
+ gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer);
+
+ if (renderbufferObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsShader(GLuint shader)
+{
+ EVENT("(GLuint shader = %d)", shader);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context && shader)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (shaderObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+GLboolean __stdcall glIsTexture(GLuint texture)
+{
+ EVENT("(GLuint texture = %d)", texture);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context && texture)
+ {
+ gl::Texture *textureObject = context->getTexture(texture);
+
+ if (textureObject)
+ {
+ return GL_TRUE;
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY, GL_FALSE);
+ }
+
+ return GL_FALSE;
+}
+
+void __stdcall glLineWidth(GLfloat width)
+{
+ EVENT("(GLfloat width = %f)", width);
+
+ try
+ {
+ if (width <= 0.0f)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setLineWidth(width);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glLinkProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ programObject->link();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glPixelStorei(GLenum pname, GLint param)
+{
+ EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (pname)
+ {
+ case GL_UNPACK_ALIGNMENT:
+ if (param != 1 && param != 2 && param != 4 && param != 8)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ context->setUnpackAlignment(param);
+ break;
+
+ case GL_PACK_ALIGNMENT:
+ if (param != 1 && param != 2 && param != 4 && param != 8)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ context->setPackAlignment(param);
+ break;
+
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glPolygonOffset(GLfloat factor, GLfloat units)
+{
+ EVENT("(GLfloat factor = %f, GLfloat units = %f)", factor, units);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setPolygonOffsetParams(factor, units);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+ EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "
+ "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = 0x%0.8p)",
+ x, y, width, height, format, type, pixels);
+
+ try
+ {
+ if (width < 0 || height < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch (format)
+ {
+ case GL_RGBA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ break;
+ default:
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
+ case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
+ break;
+ default:
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ case gl::IMPLEMENTATION_COLOR_READ_FORMAT:
+ switch (type)
+ {
+ case gl::IMPLEMENTATION_COLOR_READ_TYPE:
+ break;
+ default:
+ return error(GL_INVALID_OPERATION);
+ }
+ break;
+ default:
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->readPixels(x, y, width, height, format, type, pixels);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glReleaseShaderCompiler(void)
+{
+ EVENT("()");
+
+ try
+ {
+ gl::Shader::releaseCompiler();
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ EVENT("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
+ target, samples, internalformat, width, height);
+
+ try
+ {
+ switch (target)
+ {
+ case GL_RENDERBUFFER:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (!gl::IsColorRenderable(internalformat) && !gl::IsDepthRenderable(internalformat) && !gl::IsStencilRenderable(internalformat))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (width < 0 || height < 0 || samples < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (width > context->getMaximumRenderbufferDimension() ||
+ height > context->getMaximumRenderbufferDimension() ||
+ samples > context->getMaxSupportedSamples())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ GLuint handle = context->getRenderbufferHandle();
+ if (handle == 0)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (internalformat)
+ {
+ case GL_DEPTH_COMPONENT16:
+ context->setRenderbufferStorage(new gl::Depthbuffer(width, height, samples));
+ break;
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ context->setRenderbufferStorage(new gl::Colorbuffer(width, height, internalformat, samples));
+ break;
+ case GL_STENCIL_INDEX8:
+ context->setRenderbufferStorage(new gl::Stencilbuffer(width, height, samples));
+ break;
+ case GL_DEPTH24_STENCIL8_OES:
+ context->setRenderbufferStorage(new gl::DepthStencilbuffer(width, height, samples));
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+ glRenderbufferStorageMultisampleANGLE(target, 0, internalformat, width, height);
+}
+
+void __stdcall glSampleCoverage(GLclampf value, GLboolean invert)
+{
+ EVENT("(GLclampf value = %f, GLboolean invert = %d)", value, invert);
+
+ try
+ {
+ gl::Context* context = gl::getContext();
+
+ if (context)
+ {
+ context->setSampleCoverageParams(gl::clamp01(value), invert == GL_TRUE);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glSetFenceNV(GLuint fence, GLenum condition)
+{
+ EVENT("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition);
+
+ try
+ {
+ if (condition != GL_ALL_COMPLETED_NV)
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Fence *fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ fenceObject->setFence(condition);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
+
+ try
+ {
+ if (width < 0 || height < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context* context = gl::getContext();
+
+ if (context)
+ {
+ context->setScissorParams(x, y, width, height);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
+{
+ EVENT("(GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, "
+ "const GLvoid* binary = 0x%0.8p, GLsizei length = %d)",
+ n, shaders, binaryformat, binary, length);
+
+ try
+ {
+ // No binary shader formats are supported.
+ return error(GL_INVALID_ENUM);
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
+{
+ EVENT("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = 0x%0.8p, const GLint* length = 0x%0.8p)",
+ shader, count, string, length);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Shader *shaderObject = context->getShader(shader);
+
+ if (!shaderObject)
+ {
+ if (context->getProgram(shader))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ shaderObject->setSource(count, string, length);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask)
+{
+ glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
+}
+
+void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+{
+ EVENT("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask);
+
+ try
+ {
+ switch (face)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (func)
+ {
+ case GL_NEVER:
+ case GL_ALWAYS:
+ case GL_LESS:
+ case GL_LEQUAL:
+ case GL_EQUAL:
+ case GL_GEQUAL:
+ case GL_GREATER:
+ case GL_NOTEQUAL:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilParams(func, ref, mask);
+ }
+
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilBackParams(func, ref, mask);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glStencilMask(GLuint mask)
+{
+ glStencilMaskSeparate(GL_FRONT_AND_BACK, mask);
+}
+
+void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask)
+{
+ EVENT("(GLenum face = 0x%X, GLuint mask = %d)", face, mask);
+
+ try
+ {
+ switch (face)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilWritemask(mask);
+ }
+
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilBackWritemask(mask);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+{
+ glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass);
+}
+
+void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+{
+ EVENT("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)",
+ face, fail, zfail, zpass);
+
+ try
+ {
+ switch (face)
+ {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (fail)
+ {
+ case GL_ZERO:
+ case GL_KEEP:
+ case GL_REPLACE:
+ case GL_INCR:
+ case GL_DECR:
+ case GL_INVERT:
+ case GL_INCR_WRAP:
+ case GL_DECR_WRAP:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (zfail)
+ {
+ case GL_ZERO:
+ case GL_KEEP:
+ case GL_REPLACE:
+ case GL_INCR:
+ case GL_DECR:
+ case GL_INVERT:
+ case GL_INCR_WRAP:
+ case GL_DECR_WRAP:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (zpass)
+ {
+ case GL_ZERO:
+ case GL_KEEP:
+ case GL_REPLACE:
+ case GL_INCR:
+ case GL_DECR:
+ case GL_INVERT:
+ case GL_INCR_WRAP:
+ case GL_DECR_WRAP:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilOperations(fail, zfail, zpass);
+ }
+
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK)
+ {
+ context->setStencilBackOperations(fail, zfail, zpass);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+GLboolean __stdcall glTestFenceNV(GLuint fence)
+{
+ EVENT("(GLuint fence = %d)", fence);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Fence *fenceObject = context->getFence(fence);
+
+ if (fenceObject == NULL)
+ {
+ return error(GL_INVALID_OPERATION, GL_TRUE);
+ }
+
+ return fenceObject->testFence();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ error(GL_OUT_OF_MEMORY);
+ }
+
+ return GL_TRUE;
+}
+
+void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
+ GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, "
+ "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)",
+ target, level, internalformat, width, height, border, format, type, pixels);
+
+ try
+ {
+ if (!validImageSize(level, width, height))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (internalformat != format)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (format)
+ {
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_FLOAT:
+ case GL_HALF_FLOAT_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_RGB:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_FLOAT:
+ case GL_HALF_FLOAT_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_RGBA:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ case GL_FLOAT:
+ case GL_HALF_FLOAT_OES:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_BGRA_EXT:
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ break;
+ default:
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (border != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ if (width > (context->getMaximumTextureDimension() >> level) ||
+ height > (context->getMaximumTextureDimension() >> level))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ if (width != height)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (width > (context->getMaximumCubeTextureDimension() >> level) ||
+ height > (context->getMaximumCubeTextureDimension() >> level))
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
+ {
+ if (context->supportsCompressedTextures())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ }
+
+ if (type == GL_FLOAT)
+ {
+ if (!context->supportsFloatTextures())
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ else if (type == GL_HALF_FLOAT_OES)
+ {
+ if (!context->supportsHalfFloatTextures())
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->setImage(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ }
+ else
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ switch (target)
+ {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ texture->setImagePosX(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ texture->setImageNegX(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ texture->setImagePosY(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ texture->setImageNegY(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ texture->setImagePosZ(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ texture->setImageNegZ(level, width, height, format, type, context->getUnpackAlignment(), pixels);
+ break;
+ default: UNREACHABLE();
+ }
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param)
+{
+ glTexParameteri(target, pname, (GLint)param);
+}
+
+void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
+{
+ glTexParameteri(target, pname, (GLint)*params);
+}
+
+void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param)
+{
+ EVENT("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Texture *texture;
+
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ texture = context->getTexture2D();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture = context->getTextureCubeMap();
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ switch (pname)
+ {
+ case GL_TEXTURE_WRAP_S:
+ if (!texture->setWrapS((GLenum)param))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_WRAP_T:
+ if (!texture->setWrapT((GLenum)param))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_MIN_FILTER:
+ if (!texture->setMinFilter((GLenum)param))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ case GL_TEXTURE_MAG_FILTER:
+ if (!texture->setMagFilter((GLenum)param))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params)
+{
+ glTexParameteri(target, pname, *params);
+}
+
+void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, const GLvoid* pixels)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
+ "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, "
+ "const GLvoid* pixels = 0x%0.8p)",
+ target, level, xoffset, yoffset, width, height, format, type, pixels);
+
+ try
+ {
+ if (!gl::IsTextureTarget(target))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (!gl::CheckTextureFormatType(format, type))
+ {
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (width == 0 || height == 0 || pixels == NULL)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (level > context->getMaximumTextureLevel())
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (format == GL_FLOAT)
+ {
+ if (!context->supportsFloatTextures())
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ }
+ else if (format == GL_HALF_FLOAT_OES)
+ {
+ if (!context->supportsHalfFloatTextures())
+ {
+ return error(GL_INVALID_ENUM);
+ }
+ }
+
+ if (target == GL_TEXTURE_2D)
+ {
+ gl::Texture2D *texture = context->getTexture2D();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (texture->isCompressed())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (format != texture->getInternalFormat())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+ }
+ else if (gl::IsCubemapTextureTarget(target))
+ {
+ gl::TextureCubeMap *texture = context->getTextureCubeMap();
+
+ if (!texture)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
+ }
+ else
+ {
+ UNREACHABLE();
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform1f(GLint location, GLfloat x)
+{
+ glUniform1fv(location, 1, &x);
+}
+
+void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniform1fv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform1i(GLint location, GLint x)
+{
+ glUniform1iv(location, 1, &x);
+}
+
+void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniform1iv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y)
+{
+ GLfloat xy[2] = {x, y};
+
+ glUniform2fv(location, 1, (GLfloat*)&xy);
+}
+
+void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniform2fv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform2i(GLint location, GLint x, GLint y)
+{
+ GLint xy[4] = {x, y};
+
+ glUniform2iv(location, 1, (GLint*)&xy);
+}
+
+void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniform2iv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+ GLfloat xyz[3] = {x, y, z};
+
+ glUniform3fv(location, 1, (GLfloat*)&xyz);
+}
+
+void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniform3fv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z)
+{
+ GLint xyz[3] = {x, y, z};
+
+ glUniform3iv(location, 1, (GLint*)&xyz);
+}
+
+void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniform3iv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GLfloat xyzw[4] = {x, y, z, w};
+
+ glUniform4fv(location, 1, (GLfloat*)&xyzw);
+}
+
+void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniform4fv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+ GLint xyzw[4] = {x, y, z, w};
+
+ glUniform4iv(location, 1, (GLint*)&xyzw);
+}
+
+void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p)", location, count, v);
+
+ try
+ {
+ if (count < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniform4iv(location, count, v))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if (count < 0 || transpose != GL_FALSE)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniformMatrix2fv(location, count, value))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if (count < 0 || transpose != GL_FALSE)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniformMatrix3fv(location, count, value))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+{
+ EVENT("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p)",
+ location, count, transpose, value);
+
+ try
+ {
+ if (count < 0 || transpose != GL_FALSE)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (location == -1)
+ {
+ return;
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *program = context->getCurrentProgram();
+
+ if (!program)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ if (!program->setUniformMatrix4fv(location, count, value))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glUseProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject && program != 0)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ if (program != 0 && !programObject->isLinked())
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ context->useProgram(program);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glValidateProgram(GLuint program)
+{
+ EVENT("(GLuint program = %d)", program);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject)
+ {
+ if (context->getShader(program))
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ else
+ {
+ return error(GL_INVALID_VALUE);
+ }
+ }
+
+ programObject->validate();
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib1f(GLuint index, GLfloat x)
+{
+ EVENT("(GLuint index = %d, GLfloat x = %f)", index, x);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { x, 0, 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values)
+{
+ EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { values[0], 0, 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
+{
+ EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { x, y, 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values)
+{
+ EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { values[0], values[1], 0, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
+{
+ EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { x, y, z, 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values)
+{
+ EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { values[0], values[1], values[2], 1 };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ EVENT("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ GLfloat vals[4] = { x, y, z, w };
+ context->setVertexAttrib(index, vals);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values)
+{
+ EVENT("(GLuint index = %d, const GLfloat* values = 0x%0.8p)", index, values);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setVertexAttrib(index, values);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
+{
+ EVENT("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, "
+ "GLboolean normalized = %d, GLsizei stride = %d, const GLvoid* ptr = 0x%0.8p)",
+ index, size, type, normalized, stride, ptr);
+
+ try
+ {
+ if (index >= gl::MAX_VERTEX_ATTRIBS)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (size < 1 || size > 4)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ switch (type)
+ {
+ case GL_BYTE:
+ case GL_UNSIGNED_BYTE:
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT:
+ case GL_FIXED:
+ case GL_FLOAT:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if (stride < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized == GL_TRUE), stride, ptr);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
+{
+ EVENT("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
+
+ try
+ {
+ if (width < 0 || height < 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ context->setViewportParams(x, y, width, height);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ EVENT("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
+ "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
+ "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
+ srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+
+ try
+ {
+ switch (filter)
+ {
+ case GL_NEAREST:
+ break;
+ default:
+ return error(GL_INVALID_ENUM);
+ }
+
+ if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
+ {
+ return error(GL_INVALID_VALUE);
+ }
+
+ if (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)
+ {
+ ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation");
+ return error(GL_INVALID_OPERATION);
+ }
+
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ if (context->getReadFramebufferHandle() == context->getDrawFramebufferHandle())
+ {
+ ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");
+ return error(GL_INVALID_OPERATION);
+ }
+
+ context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask);
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
+ GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+{
+ EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
+ "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, "
+ "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* pixels = 0x%0.8p)",
+ target, level, internalformat, width, height, depth, border, format, type, pixels);
+
+ try
+ {
+ UNIMPLEMENTED(); // FIXME
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+__eglMustCastToProperFunctionPointerType __stdcall glGetProcAddress(const char *procname)
+{
+ struct Extension
+ {
+ const char *name;
+ __eglMustCastToProperFunctionPointerType address;
+ };
+
+ static const Extension glExtensions[] =
+ {
+ {"glTexImage3DOES", (__eglMustCastToProperFunctionPointerType)glTexImage3DOES},
+ {"glBlitFramebufferANGLE", (__eglMustCastToProperFunctionPointerType)glBlitFramebufferANGLE},
+ {"glRenderbufferStorageMultisampleANGLE", (__eglMustCastToProperFunctionPointerType)glRenderbufferStorageMultisampleANGLE},
+ {"glDeleteFencesNV", (__eglMustCastToProperFunctionPointerType)glDeleteFencesNV},
+ {"glGenFencesNV", (__eglMustCastToProperFunctionPointerType)glGenFencesNV},
+ {"glIsFenceNV", (__eglMustCastToProperFunctionPointerType)glIsFenceNV},
+ {"glTestFenceNV", (__eglMustCastToProperFunctionPointerType)glTestFenceNV},
+ {"glGetFenceivNV", (__eglMustCastToProperFunctionPointerType)glGetFenceivNV},
+ {"glFinishFenceNV", (__eglMustCastToProperFunctionPointerType)glFinishFenceNV},
+ {"glSetFenceNV", (__eglMustCastToProperFunctionPointerType)glSetFenceNV},
+ };
+
+ for (int ext = 0; ext < sizeof(glExtensions) / sizeof(Extension); ext++)
+ {
+ if (strcmp(procname, glExtensions[ext].name) == 0)
+ {
+ return (__eglMustCastToProperFunctionPointerType)glExtensions[ext].address;
+ }
+ }
+
+ return NULL;
+}
+
+void __stdcall glBindTexImage(egl::Surface *surface)
+{
+ EVENT("(egl::Surface* surface = 0x%0.8p)",
+ surface);
+
+ try
+ {
+ gl::Context *context = gl::getContext();
+
+ if (context)
+ {
+ gl::Texture2D *textureObject = context->getTexture2D();
+
+ if (textureObject)
+ {
+ textureObject->bindTexImage(surface);
+ }
+ }
+ }
+ catch(std::bad_alloc&)
+ {
+ return error(GL_OUT_OF_MEMORY);
+ }
+}
+
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.def b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.def
new file mode 100644
index 000000000..b91217199
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.def
@@ -0,0 +1,164 @@
+LIBRARY libGLESv2
+EXPORTS
+ glActiveTexture @1
+ glAttachShader @2
+ glBindAttribLocation @3
+ glBindBuffer @4
+ glBindFramebuffer @5
+ glBindRenderbuffer @6
+ glBindTexture @7
+ glBlendColor @8
+ glBlendEquation @9
+ glBlendEquationSeparate @10
+ glBlendFunc @11
+ glBlendFuncSeparate @12
+ glBufferData @13
+ glBufferSubData @14
+ glCheckFramebufferStatus @15
+ glClear @16
+ glClearColor @17
+ glClearDepthf @18
+ glClearStencil @19
+ glColorMask @20
+ glCompileShader @21
+ glCompressedTexImage2D @22
+ glCompressedTexSubImage2D @23
+ glCopyTexImage2D @24
+ glCopyTexSubImage2D @25
+ glCreateProgram @26
+ glCreateShader @27
+ glCullFace @28
+ glDeleteBuffers @29
+ glDeleteFramebuffers @30
+ glDeleteProgram @32
+ glDeleteRenderbuffers @33
+ glDeleteShader @34
+ glDeleteTextures @31
+ glDepthFunc @36
+ glDepthMask @37
+ glDepthRangef @38
+ glDetachShader @35
+ glDisable @39
+ glDisableVertexAttribArray @40
+ glDrawArrays @41
+ glDrawElements @42
+ glEnable @43
+ glEnableVertexAttribArray @44
+ glFinish @45
+ glFlush @46
+ glFramebufferRenderbuffer @47
+ glFramebufferTexture2D @48
+ glFrontFace @49
+ glGenBuffers @50
+ glGenFramebuffers @52
+ glGenRenderbuffers @53
+ glGenTextures @54
+ glGenerateMipmap @51
+ glGetActiveAttrib @55
+ glGetActiveUniform @56
+ glGetAttachedShaders @57
+ glGetAttribLocation @58
+ glGetBooleanv @59
+ glGetBufferParameteriv @60
+ glGetError @61
+ glGetFloatv @62
+ glGetFramebufferAttachmentParameteriv @63
+ glGetIntegerv @64
+ glGetProgramInfoLog @66
+ glGetProgramiv @65
+ glGetRenderbufferParameteriv @67
+ glGetShaderInfoLog @69
+ glGetShaderPrecisionFormat @70
+ glGetShaderSource @71
+ glGetShaderiv @68
+ glGetString @72
+ glGetTexParameterfv @73
+ glGetTexParameteriv @74
+ glGetUniformLocation @77
+ glGetUniformfv @75
+ glGetUniformiv @76
+ glGetVertexAttribPointerv @80
+ glGetVertexAttribfv @78
+ glGetVertexAttribiv @79
+ glHint @81
+ glIsBuffer @82
+ glIsEnabled @83
+ glIsFramebuffer @84
+ glIsProgram @85
+ glIsRenderbuffer @86
+ glIsShader @87
+ glIsTexture @88
+ glLineWidth @89
+ glLinkProgram @90
+ glPixelStorei @91
+ glPolygonOffset @92
+ glReadPixels @93
+ glReleaseShaderCompiler @94
+ glRenderbufferStorage @95
+ glSampleCoverage @96
+ glScissor @97
+ glShaderBinary @98
+ glShaderSource @99
+ glStencilFunc @100
+ glStencilFuncSeparate @101
+ glStencilMask @102
+ glStencilMaskSeparate @103
+ glStencilOp @104
+ glStencilOpSeparate @105
+ glTexImage2D @106
+ glTexParameterf @107
+ glTexParameterfv @108
+ glTexParameteri @109
+ glTexParameteriv @110
+ glTexSubImage2D @111
+ glUniform1f @112
+ glUniform1fv @113
+ glUniform1i @114
+ glUniform1iv @115
+ glUniform2f @116
+ glUniform2fv @117
+ glUniform2i @118
+ glUniform2iv @119
+ glUniform3f @120
+ glUniform3fv @121
+ glUniform3i @122
+ glUniform3iv @123
+ glUniform4f @124
+ glUniform4fv @125
+ glUniform4i @126
+ glUniform4iv @127
+ glUniformMatrix2fv @128
+ glUniformMatrix3fv @129
+ glUniformMatrix4fv @130
+ glUseProgram @131
+ glValidateProgram @132
+ glVertexAttrib1f @133
+ glVertexAttrib1fv @134
+ glVertexAttrib2f @135
+ glVertexAttrib2fv @136
+ glVertexAttrib3f @137
+ glVertexAttrib3fv @138
+ glVertexAttrib4f @139
+ glVertexAttrib4fv @140
+ glVertexAttribPointer @141
+ glViewport @142
+
+ ; Extensions
+ glTexImage3DOES @143
+ glBlitFramebufferANGLE @149
+ glRenderbufferStorageMultisampleANGLE @150
+ glDeleteFencesNV @151
+ glFinishFenceNV @152
+ glGenFencesNV @153
+ glGetFenceivNV @154
+ glIsFenceNV @155
+ glSetFenceNV @156
+ glTestFenceNV @157
+
+ ; EGL dependencies
+ glCreateContext @144 NONAME
+ glDestroyContext @145 NONAME
+ glMakeCurrent @146 NONAME
+ glGetCurrentContext @147 NONAME
+ glGetProcAddress @148 NONAME
+ glBindTexImage @158 NONAME
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.rc b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.rc
new file mode 100644
index 000000000..4e733bdaf
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.rc
@@ -0,0 +1,102 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "../common/version.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "#include ""../common/version.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,BUILD_VERSION,BUILD_REVISION
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", "ANGLE libGLESv2 Dynamic Link Library"
+ VALUE "FileVersion", VERSION_STRING
+ VALUE "InternalName", "libGLESv2"
+ VALUE "LegalCopyright", "Copyright (C) 2011 Google Inc."
+ VALUE "OriginalFilename", "libGLESv2.dll"
+ VALUE "PrivateBuild", VERSION_STRING
+ VALUE "ProductName", "ANGLE libGLESv2 Dynamic Link Library"
+ VALUE "ProductVersion", VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.vcproj b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.vcproj
new file mode 100644
index 000000000..5bb2e68a9
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/libGLESv2.vcproj
@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="libGLESv2"
+ ProjectGUID="{B5871A7A-968C-42E3-A33B-981E6F448E78}"
+ RootNamespace="libGLESv2"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(ProjectDir)/..; $(ProjectDir)/../../include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="d3d9.lib D3dx9.lib d3dcompiler.lib"
+ LinkIncremental="2"
+ ModuleDefinitionFile="libGLESv2.def"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="@echo on&#x0D;&#x0A;mkdir &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;copy &quot;$(OutDir)\libGLESv2.dll&quot; &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;copy &quot;$(OutDir)\libGLESv2.lib&quot; &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;@echo off&#x0D;&#x0A;"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="2"
+ AdditionalIncludeDirectories="$(ProjectDir)/..; $(ProjectDir)/../../include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBGLESV2_EXPORTS;_CRT_SECURE_NO_DEPRECATE;NOMINMAX;_SECURE_SCL=0"
+ RuntimeLibrary="0"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="d3d9.lib D3dx9.lib d3dcompiler.lib"
+ LinkIncremental="1"
+ IgnoreAllDefaultLibraries="false"
+ ModuleDefinitionFile="libGLESv2.def"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="@echo on&#x0D;&#x0A;mkdir &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;copy &quot;$(OutDir)\libGLESv2.dll&quot; &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;copy &quot;$(OutDir)\libGLESv2.lib&quot; &quot;$(ProjectDir)..\..\lib\$(ConfigurationName)\&quot;&#x0D;&#x0A;@echo off&#x0D;&#x0A;"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\Blit.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Buffer.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Context.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\common\debug.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Fence.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Framebuffer.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\HandleAllocator.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\IndexDataManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\libGLESv2.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Program.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\RefCountObject.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Renderbuffer.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ResourceManager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Shader.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Texture.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\utilities.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\VertexDataManager.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\Blit.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Buffer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Context.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Fence.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Framebuffer.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\GLES2\gl2.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\GLES2\gl2ext.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\include\GLES2\gl2platform.h"
+ >
+ </File>
+ <File
+ RelativePath=".\HandleAllocator.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IndexDataManager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\main.h"
+ >
+ </File>
+ <File
+ RelativePath=".\mathutil.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Program.h"
+ >
+ </File>
+ <File
+ RelativePath=".\RefCountObject.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Renderbuffer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\ResourceManager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Shader.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Texture.h"
+ >
+ </File>
+ <File
+ RelativePath=".\utilities.h"
+ >
+ </File>
+ <File
+ RelativePath="..\common\version.h"
+ >
+ </File>
+ <File
+ RelativePath=".\vertexconversion.h"
+ >
+ </File>
+ <File
+ RelativePath=".\VertexDataManager.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\libGLESv2.def"
+ >
+ </File>
+ <File
+ RelativePath=".\libGLESv2.rc"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/main.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/main.cpp
new file mode 100644
index 000000000..ad1156309
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/main.cpp
@@ -0,0 +1,143 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// main.cpp: DLL entry point and management of thread-local data.
+
+#include "libGLESv2/main.h"
+
+#include "common/debug.h"
+#include "libEGL/Surface.h"
+
+#include "libGLESv2/Framebuffer.h"
+
+static DWORD currentTLS = TLS_OUT_OF_INDEXES;
+
+BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
+{
+ switch (reason)
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ currentTLS = TlsAlloc();
+
+ if (currentTLS == TLS_OUT_OF_INDEXES)
+ {
+ return FALSE;
+ }
+ }
+ // Fall throught to initialize index
+ case DLL_THREAD_ATTACH:
+ {
+ gl::Current *current = (gl::Current*)LocalAlloc(LPTR, sizeof(gl::Current));
+
+ if (current)
+ {
+ TlsSetValue(currentTLS, current);
+
+ current->context = NULL;
+ current->display = NULL;
+ }
+ }
+ break;
+ case DLL_THREAD_DETACH:
+ {
+ void *current = TlsGetValue(currentTLS);
+
+ if (current)
+ {
+ LocalFree((HLOCAL)current);
+ }
+ }
+ break;
+ case DLL_PROCESS_DETACH:
+ {
+ void *current = TlsGetValue(currentTLS);
+
+ if (current)
+ {
+ LocalFree((HLOCAL)current);
+ }
+
+ TlsFree(currentTLS);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+namespace gl
+{
+void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface)
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ current->context = context;
+ current->display = display;
+
+ if (context && display && surface)
+ {
+ context->makeCurrent(display, surface);
+ }
+}
+
+Context *getContext()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->context;
+}
+
+egl::Display *getDisplay()
+{
+ Current *current = (Current*)TlsGetValue(currentTLS);
+
+ return current->display;
+}
+
+IDirect3DDevice9 *getDevice()
+{
+ egl::Display *display = getDisplay();
+
+ return display->getDevice();
+}
+}
+
+// Records an error code
+void error(GLenum errorCode)
+{
+ gl::Context *context = glGetCurrentContext();
+
+ if (context)
+ {
+ switch (errorCode)
+ {
+ case GL_INVALID_ENUM:
+ context->recordInvalidEnum();
+ TRACE("\t! Error generated: invalid enum\n");
+ break;
+ case GL_INVALID_VALUE:
+ context->recordInvalidValue();
+ TRACE("\t! Error generated: invalid value\n");
+ break;
+ case GL_INVALID_OPERATION:
+ context->recordInvalidOperation();
+ TRACE("\t! Error generated: invalid operation\n");
+ break;
+ case GL_OUT_OF_MEMORY:
+ context->recordOutOfMemory();
+ TRACE("\t! Error generated: out of memory\n");
+ break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION:
+ context->recordInvalidFramebufferOperation();
+ TRACE("\t! Error generated: invalid framebuffer operation\n");
+ break;
+ default: UNREACHABLE();
+ }
+ }
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/main.h b/Source/ThirdParty/ANGLE/src/libGLESv2/main.h
new file mode 100644
index 000000000..7f9c8807b
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/main.h
@@ -0,0 +1,47 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// main.h: Management of thread-local data.
+
+#ifndef LIBGLESV2_MAIN_H_
+#define LIBGLESV2_MAIN_H_
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include "common/debug.h"
+#include "libEGL/Display.h"
+
+#include "libGLESv2/Context.h"
+
+namespace gl
+{
+struct Current
+{
+ Context *context;
+ egl::Display *display;
+};
+
+void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface);
+
+Context *getContext();
+egl::Display *getDisplay();
+
+IDirect3DDevice9 *getDevice();
+}
+
+void error(GLenum errorCode);
+
+template<class T>
+const T &error(GLenum errorCode, const T &returnValue)
+{
+ error(errorCode);
+
+ return returnValue;
+}
+
+#endif // LIBGLESV2_MAIN_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/mathutil.h b/Source/ThirdParty/ANGLE/src/libGLESv2/mathutil.h
new file mode 100644
index 000000000..7ca2d9ffd
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/mathutil.h
@@ -0,0 +1,119 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// mathutil.h: Math and bit manipulation functions.
+
+#ifndef LIBGLESV2_MATHUTIL_H_
+#define LIBGLESV2_MATHUTIL_H_
+
+#include <intrin.h>
+#include <math.h>
+#include <windows.h>
+
+namespace gl
+{
+inline bool isPow2(int x)
+{
+ return (x & (x - 1)) == 0 && (x != 0);
+}
+
+inline int log2(int x)
+{
+ int r = 0;
+ while ((x >> r) > 1) r++;
+ return r;
+}
+
+inline unsigned int ceilPow2(unsigned int x)
+{
+ if (x != 0) x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x++;
+
+ return x;
+}
+
+template<typename T, typename MIN, typename MAX>
+inline T clamp(T x, MIN min, MAX max)
+{
+ return x < min ? min : (x > max ? max : x);
+}
+
+inline float clamp01(float x)
+{
+ return clamp(x, 0.0f, 1.0f);
+}
+
+template<const int n>
+inline unsigned int unorm(float x)
+{
+ const unsigned int max = 0xFFFFFFFF >> (32 - n);
+
+ if (x > 1)
+ {
+ return max;
+ }
+ else if (x < 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return (unsigned int)(max * x + 0.5f);
+ }
+}
+
+inline RECT transformPixelRect(GLint x, GLint y, GLint w, GLint h, GLint surfaceHeight)
+{
+ RECT rect = {x,
+ surfaceHeight - y - h,
+ x + w,
+ surfaceHeight - y};
+ return rect;
+}
+
+inline int transformPixelYOffset(GLint yoffset, GLint h, GLint surfaceHeight)
+{
+ return surfaceHeight - yoffset - h;
+}
+
+inline GLenum adjustWinding(GLenum winding)
+{
+ ASSERT(winding == GL_CW || winding == GL_CCW);
+ return winding == GL_CW ? GL_CCW : GL_CW;
+}
+
+inline bool supportsSSE2()
+{
+ static bool checked = false;
+ static bool supports = false;
+
+ if (checked)
+ {
+ return supports;
+ }
+
+ int info[4];
+ __cpuid(info, 0);
+
+ if (info[0] >= 1)
+ {
+ __cpuid(info, 1);
+
+ supports = (info[3] >> 26) & 1;
+ }
+
+ checked = true;
+
+ return supports;
+}
+}
+
+#endif // LIBGLESV2_MATHUTIL_H_
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/resource.h b/Source/ThirdParty/ANGLE/src/libGLESv2/resource.h
new file mode 100644
index 000000000..39adaad0d
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by libGLESv2.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.cpp
new file mode 100644
index 000000000..ba23fd365
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.cpp
@@ -0,0 +1,882 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// utilities.cpp: Conversion functions and other utility routines.
+
+#include "libGLESv2/utilities.h"
+
+#include <limits>
+#include <stdio.h>
+#include <windows.h>
+
+#include "common/debug.h"
+
+#include "libGLESv2/mathutil.h"
+#include "libGLESv2/Context.h"
+
+namespace gl
+{
+
+int UniformComponentCount(GLenum type)
+{
+ switch (type)
+ {
+ case GL_BOOL:
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ return 1;
+ case GL_BOOL_VEC2:
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ return 2;
+ case GL_INT_VEC3:
+ case GL_FLOAT_VEC3:
+ case GL_BOOL_VEC3:
+ return 3;
+ case GL_BOOL_VEC4:
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_FLOAT_MAT2:
+ return 4;
+ case GL_FLOAT_MAT3:
+ return 9;
+ case GL_FLOAT_MAT4:
+ return 16;
+ default:
+ UNREACHABLE();
+ }
+
+ return 0;
+}
+
+GLenum UniformComponentType(GLenum type)
+{
+ switch(type)
+ {
+ case GL_BOOL:
+ case GL_BOOL_VEC2:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ return GL_BOOL;
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
+ return GL_FLOAT;
+ case GL_INT:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ return GL_INT;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_NONE;
+}
+
+size_t UniformTypeSize(GLenum type)
+{
+ switch(type)
+ {
+ case GL_BOOL: return sizeof(GLboolean);
+ case GL_FLOAT: return sizeof(GLfloat);
+ case GL_INT: return sizeof(GLint);
+ }
+
+ return UniformTypeSize(UniformComponentType(type)) * UniformComponentCount(type);
+}
+
+int VariableRowCount(GLenum type)
+{
+ switch (type)
+ {
+ case GL_NONE:
+ return 0;
+ case GL_BOOL:
+ case GL_FLOAT:
+ case GL_INT:
+ case GL_BOOL_VEC2:
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_FLOAT_VEC3:
+ case GL_BOOL_VEC3:
+ case GL_BOOL_VEC4:
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ return 1;
+ case GL_FLOAT_MAT2:
+ return 2;
+ case GL_FLOAT_MAT3:
+ return 3;
+ case GL_FLOAT_MAT4:
+ return 4;
+ default:
+ UNREACHABLE();
+ }
+
+ return 0;
+}
+
+int VariableColumnCount(GLenum type)
+{
+ switch (type)
+ {
+ case GL_NONE:
+ return 0;
+ case GL_BOOL:
+ case GL_FLOAT:
+ case GL_INT:
+ return 1;
+ case GL_BOOL_VEC2:
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_FLOAT_MAT2:
+ return 2;
+ case GL_INT_VEC3:
+ case GL_FLOAT_VEC3:
+ case GL_BOOL_VEC3:
+ case GL_FLOAT_MAT3:
+ return 3;
+ case GL_BOOL_VEC4:
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_FLOAT_MAT4:
+ return 4;
+ default:
+ UNREACHABLE();
+ }
+
+ return 0;
+}
+
+int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize)
+{
+ ASSERT(allocationSize <= bitsSize);
+
+ unsigned int mask = std::numeric_limits<unsigned int>::max() >> (std::numeric_limits<unsigned int>::digits - allocationSize);
+
+ for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++)
+ {
+ if ((*bits & mask) == 0)
+ {
+ *bits |= mask;
+ return i;
+ }
+
+ mask <<= 1;
+ }
+
+ return -1;
+}
+
+GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment)
+{
+ ASSERT(alignment > 0 && isPow2(alignment));
+
+ GLsizei rawPitch = ComputePixelSize(format, type) * width;
+ return (rawPitch + alignment - 1) & ~(alignment - 1);
+}
+
+GLsizei ComputeCompressedPitch(GLsizei width, GLenum format)
+{
+ return ComputeCompressedSize(width, 1, format);
+}
+
+GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format)
+{
+ switch (format)
+ {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ break;
+ default:
+ return 0;
+ }
+
+ return 8 * (GLsizei)ceil((float)width / 4.0f) * (GLsizei)ceil((float)height / 4.0f);
+}
+
+bool IsCompressed(GLenum format)
+{
+ if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
+ format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Returns the size, in bytes, of a single texel in an Image
+int ComputePixelSize(GLenum format, GLenum type)
+{
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ switch (format)
+ {
+ case GL_ALPHA: return sizeof(unsigned char);
+ case GL_LUMINANCE: return sizeof(unsigned char);
+ case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2;
+ case GL_RGB: return sizeof(unsigned char) * 3;
+ case GL_RGBA: return sizeof(unsigned char) * 4;
+ case GL_BGRA_EXT: return sizeof(unsigned char) * 4;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ return sizeof(unsigned short);
+ case GL_FLOAT:
+ switch (format)
+ {
+ case GL_ALPHA: return sizeof(float);
+ case GL_LUMINANCE: return sizeof(float);
+ case GL_LUMINANCE_ALPHA: return sizeof(float) * 2;
+ case GL_RGB: return sizeof(float) * 3;
+ case GL_RGBA: return sizeof(float) * 4;
+ default: UNREACHABLE();
+ }
+ break;
+ case GL_HALF_FLOAT_OES:
+ switch (format)
+ {
+ case GL_ALPHA: return sizeof(unsigned short);
+ case GL_LUMINANCE: return sizeof(unsigned short);
+ case GL_LUMINANCE_ALPHA: return sizeof(unsigned short) * 2;
+ case GL_RGB: return sizeof(unsigned short) * 3;
+ case GL_RGBA: return sizeof(unsigned short) * 4;
+ default: UNREACHABLE();
+ }
+ break;
+ default: UNREACHABLE();
+ }
+
+ return 0;
+}
+
+bool IsCubemapTextureTarget(GLenum target)
+{
+ return (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X && target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
+}
+
+bool IsTextureTarget(GLenum target)
+{
+ return target == GL_TEXTURE_2D || IsCubemapTextureTarget(target);
+}
+
+// Verify that format/type are one of the combinations from table 3.4.
+bool CheckTextureFormatType(GLenum format, GLenum type)
+{
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ switch (format)
+ {
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ case GL_RGB:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ return true;
+
+ default:
+ return false;
+ }
+
+ case GL_FLOAT:
+ case GL_HALF_FLOAT_OES:
+ switch (format)
+ {
+ case GL_RGBA:
+ case GL_RGB:
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ return true;
+
+ default:
+ return false;
+ }
+
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ return (format == GL_RGBA);
+
+ case GL_UNSIGNED_SHORT_5_6_5:
+ return (format == GL_RGB);
+
+ default:
+ return false;
+ }
+}
+
+bool IsColorRenderable(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ return true;
+ case GL_DEPTH_COMPONENT16:
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES:
+ return false;
+ default:
+ UNIMPLEMENTED();
+ }
+
+ return false;
+}
+
+bool IsDepthRenderable(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH24_STENCIL8_OES:
+ return true;
+ case GL_STENCIL_INDEX8:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ return false;
+ default:
+ UNIMPLEMENTED();
+ }
+
+ return false;
+}
+
+bool IsStencilRenderable(GLenum internalformat)
+{
+ switch (internalformat)
+ {
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES:
+ return true;
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGB565:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ case GL_DEPTH_COMPONENT16:
+ return false;
+ default:
+ UNIMPLEMENTED();
+ }
+
+ return false;
+}
+
+}
+
+namespace es2dx
+{
+
+D3DCMPFUNC ConvertComparison(GLenum comparison)
+{
+ D3DCMPFUNC d3dComp = D3DCMP_ALWAYS;
+ switch (comparison)
+ {
+ case GL_NEVER: d3dComp = D3DCMP_NEVER; break;
+ case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break;
+ case GL_LESS: d3dComp = D3DCMP_LESS; break;
+ case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break;
+ case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break;
+ case GL_GREATER: d3dComp = D3DCMP_GREATER; break;
+ case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break;
+ case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dComp;
+}
+
+D3DCOLOR ConvertColor(gl::Color color)
+{
+ return D3DCOLOR_RGBA(gl::unorm<8>(color.red),
+ gl::unorm<8>(color.green),
+ gl::unorm<8>(color.blue),
+ gl::unorm<8>(color.alpha));
+}
+
+D3DBLEND ConvertBlendFunc(GLenum blend)
+{
+ D3DBLEND d3dBlend = D3DBLEND_ZERO;
+
+ switch (blend)
+ {
+ case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break;
+ case GL_ONE: d3dBlend = D3DBLEND_ONE; break;
+ case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break;
+ case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break;
+ case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break;
+ case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break;
+ case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break;
+ case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break;
+ case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break;
+ case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break;
+ case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break;
+ case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
+ case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break;
+ case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dBlend;
+}
+
+D3DBLENDOP ConvertBlendOp(GLenum blendOp)
+{
+ D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD;
+
+ switch (blendOp)
+ {
+ case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break;
+ case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break;
+ case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dBlendOp;
+}
+
+D3DSTENCILOP ConvertStencilOp(GLenum stencilOp)
+{
+ D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP;
+
+ switch (stencilOp)
+ {
+ case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break;
+ case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break;
+ case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break;
+ case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break;
+ case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break;
+ case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break;
+ case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break;
+ case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dStencilOp;
+}
+
+D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap)
+{
+ D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP;
+
+ switch (wrap)
+ {
+ case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break;
+ case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break;
+ case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dWrap;
+}
+
+D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace)
+{
+ D3DCULL cull = D3DCULL_CCW;
+ switch (cullFace)
+ {
+ case GL_FRONT:
+ cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW);
+ break;
+ case GL_BACK:
+ cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW);
+ break;
+ case GL_FRONT_AND_BACK:
+ cull = D3DCULL_NONE; // culling will be handled during draw
+ break;
+ default: UNREACHABLE();
+ }
+
+ return cull;
+}
+
+D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace)
+{
+ D3DCUBEMAP_FACES face = D3DCUBEMAP_FACE_POSITIVE_X;
+
+ // Map a cube map texture target to the corresponding D3D surface index. Note that the
+ // Y faces are swapped because the Y coordinate to the texture lookup intrinsic functions
+ // are negated in the pixel shader.
+ switch (cubeFace)
+ {
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ face = D3DCUBEMAP_FACE_POSITIVE_X;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ face = D3DCUBEMAP_FACE_NEGATIVE_X;
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ face = D3DCUBEMAP_FACE_NEGATIVE_Y;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ face = D3DCUBEMAP_FACE_POSITIVE_Y;
+ break;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ face = D3DCUBEMAP_FACE_POSITIVE_Z;
+ break;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ face = D3DCUBEMAP_FACE_NEGATIVE_Z;
+ break;
+ default: UNREACHABLE();
+ }
+
+ return face;
+}
+
+DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha)
+{
+ return (red ? D3DCOLORWRITEENABLE_RED : 0) |
+ (green ? D3DCOLORWRITEENABLE_GREEN : 0) |
+ (blue ? D3DCOLORWRITEENABLE_BLUE : 0) |
+ (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0);
+}
+
+D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter)
+{
+ D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT;
+ switch (magFilter)
+ {
+ case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break;
+ case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break;
+ default: UNREACHABLE();
+ }
+
+ return d3dMagFilter;
+}
+
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter)
+{
+ switch (minFilter)
+ {
+ case GL_NEAREST:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_NONE;
+ break;
+ case GL_LINEAR:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_NONE;
+ break;
+ case GL_NEAREST_MIPMAP_NEAREST:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_POINT;
+ break;
+ case GL_LINEAR_MIPMAP_NEAREST:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_POINT;
+ break;
+ case GL_NEAREST_MIPMAP_LINEAR:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_LINEAR;
+ break;
+ case GL_LINEAR_MIPMAP_LINEAR:
+ *d3dMinFilter = D3DTEXF_LINEAR;
+ *d3dMipFilter = D3DTEXF_LINEAR;
+ break;
+ default:
+ *d3dMinFilter = D3DTEXF_POINT;
+ *d3dMipFilter = D3DTEXF_NONE;
+ UNREACHABLE();
+ }
+}
+
+bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
+ D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount)
+{
+ switch (primitiveType)
+ {
+ case GL_POINTS:
+ *d3dPrimitiveType = D3DPT_POINTLIST;
+ *d3dPrimitiveCount = elementCount;
+ break;
+ case GL_LINES:
+ *d3dPrimitiveType = D3DPT_LINELIST;
+ *d3dPrimitiveCount = elementCount / 2;
+ break;
+ case GL_LINE_LOOP:
+ *d3dPrimitiveType = D3DPT_LINESTRIP;
+ *d3dPrimitiveCount = elementCount - 1; // D3D doesn't support line loops, so we draw the last line separately
+ break;
+ case GL_LINE_STRIP:
+ *d3dPrimitiveType = D3DPT_LINESTRIP;
+ *d3dPrimitiveCount = elementCount - 1;
+ break;
+ case GL_TRIANGLES:
+ *d3dPrimitiveType = D3DPT_TRIANGLELIST;
+ *d3dPrimitiveCount = elementCount / 3;
+ break;
+ case GL_TRIANGLE_STRIP:
+ *d3dPrimitiveType = D3DPT_TRIANGLESTRIP;
+ *d3dPrimitiveCount = elementCount - 2;
+ break;
+ case GL_TRIANGLE_FAN:
+ *d3dPrimitiveType = D3DPT_TRIANGLEFAN;
+ *d3dPrimitiveCount = elementCount - 2;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+D3DFORMAT ConvertRenderbufferFormat(GLenum format)
+{
+ switch (format)
+ {
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ case GL_RGBA8_OES: return D3DFMT_A8R8G8B8;
+ case GL_RGB565: return D3DFMT_R5G6B5;
+ case GL_RGB8_OES: return D3DFMT_X8R8G8B8;
+ case GL_DEPTH_COMPONENT16:
+ case GL_STENCIL_INDEX8:
+ case GL_DEPTH24_STENCIL8_OES: return D3DFMT_D24S8;
+ default: UNREACHABLE(); return D3DFMT_A8R8G8B8;
+ }
+}
+
+D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples)
+{
+ if (samples <= 1)
+ return D3DMULTISAMPLE_NONE;
+ else
+ return (D3DMULTISAMPLE_TYPE)samples;
+}
+
+}
+
+namespace dx2es
+{
+
+unsigned int GetStencilSize(D3DFORMAT stencilFormat)
+{
+ switch(stencilFormat)
+ {
+ case D3DFMT_D24FS8:
+ case D3DFMT_D24S8:
+ return 8;
+ case D3DFMT_D24X4S4:
+ return 4;
+ case D3DFMT_D15S1:
+ return 1;
+ case D3DFMT_D16_LOCKABLE:
+ case D3DFMT_D32:
+ case D3DFMT_D24X8:
+ case D3DFMT_D32F_LOCKABLE:
+ case D3DFMT_D16:
+ return 0;
+ //case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only
+ //case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetAlphaSize(D3DFORMAT colorFormat)
+{
+ switch (colorFormat)
+ {
+ case D3DFMT_A16B16G16R16F:
+ return 16;
+ case D3DFMT_A32B32G32R32F:
+ return 32;
+ case D3DFMT_A2R10G10B10:
+ return 2;
+ case D3DFMT_A8R8G8B8:
+ return 8;
+ case D3DFMT_A1R5G5B5:
+ return 1;
+ case D3DFMT_X8R8G8B8:
+ case D3DFMT_R5G6B5:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetRedSize(D3DFORMAT colorFormat)
+{
+ switch (colorFormat)
+ {
+ case D3DFMT_A16B16G16R16F:
+ return 16;
+ case D3DFMT_A32B32G32R32F:
+ return 32;
+ case D3DFMT_A2R10G10B10:
+ return 10;
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ return 8;
+ case D3DFMT_A1R5G5B5:
+ case D3DFMT_R5G6B5:
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetGreenSize(D3DFORMAT colorFormat)
+{
+ switch (colorFormat)
+ {
+ case D3DFMT_A16B16G16R16F:
+ return 16;
+ case D3DFMT_A32B32G32R32F:
+ return 32;
+ case D3DFMT_A2R10G10B10:
+ return 10;
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ return 8;
+ case D3DFMT_A1R5G5B5:
+ return 5;
+ case D3DFMT_R5G6B5:
+ return 6;
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetBlueSize(D3DFORMAT colorFormat)
+{
+ switch (colorFormat)
+ {
+ case D3DFMT_A16B16G16R16F:
+ return 16;
+ case D3DFMT_A32B32G32R32F:
+ return 32;
+ case D3DFMT_A2R10G10B10:
+ return 10;
+ case D3DFMT_A8R8G8B8:
+ case D3DFMT_X8R8G8B8:
+ return 8;
+ case D3DFMT_A1R5G5B5:
+ case D3DFMT_R5G6B5:
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+unsigned int GetDepthSize(D3DFORMAT depthFormat)
+{
+ switch (depthFormat)
+ {
+ case D3DFMT_D16_LOCKABLE: return 16;
+ case D3DFMT_D32: return 32;
+ case D3DFMT_D15S1: return 15;
+ case D3DFMT_D24S8: return 24;
+ case D3DFMT_D24X8: return 24;
+ case D3DFMT_D24X4S4: return 24;
+ case D3DFMT_D16: return 16;
+ case D3DFMT_D32F_LOCKABLE: return 32;
+ case D3DFMT_D24FS8: return 24;
+ //case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only
+ //case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only
+ default: return 0;
+ }
+}
+
+GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type)
+{
+ if (type == D3DMULTISAMPLE_NONMASKABLE)
+ return 0;
+ else
+ return type;
+}
+
+GLenum ConvertBackBufferFormat(D3DFORMAT format)
+{
+ switch (format)
+ {
+ case D3DFMT_A4R4G4B4: return GL_RGBA4;
+ case D3DFMT_A8R8G8B8: return GL_RGBA8_OES;
+ case D3DFMT_A1R5G5B5: return GL_RGB5_A1;
+ case D3DFMT_R5G6B5: return GL_RGB565;
+ case D3DFMT_X8R8G8B8: return GL_RGB8_OES;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_RGBA4;
+}
+
+GLenum ConvertDepthStencilFormat(D3DFORMAT format)
+{
+ switch (format)
+ {
+ case D3DFMT_D16:
+ case D3DFMT_D24X8:
+ return GL_DEPTH_COMPONENT16;
+ case D3DFMT_D24S8:
+ return GL_DEPTH24_STENCIL8_OES;
+ default:
+ UNREACHABLE();
+ }
+
+ return GL_DEPTH24_STENCIL8_OES;
+}
+
+}
+
+std::string getTempPath()
+{
+ char path[MAX_PATH];
+ DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path);
+ if (pathLen == 0)
+ {
+ UNREACHABLE();
+ return std::string();
+ }
+
+ UINT unique = GetTempFileNameA(path, "sh", 0, path);
+ if (unique == 0)
+ {
+ UNREACHABLE();
+ return std::string();
+ }
+
+ return path;
+}
+
+void writeFile(const char* path, const void* content, size_t size)
+{
+ FILE* file = fopen(path, "w");
+ if (!file)
+ {
+ UNREACHABLE();
+ return;
+ }
+
+ fwrite(content, sizeof(char), size, file);
+ fclose(file);
+}
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.h b/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.h
new file mode 100644
index 000000000..bf7f4f934
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/utilities.h
@@ -0,0 +1,87 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// utilities.h: Conversion functions and other utility routines.
+
+#ifndef LIBGLESV2_UTILITIES_H
+#define LIBGLESV2_UTILITIES_H
+
+#define GL_APICALL
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <d3d9.h>
+
+#include <string>
+
+namespace gl
+{
+
+struct Color;
+
+int UniformComponentCount(GLenum type);
+GLenum UniformComponentType(GLenum type);
+size_t UniformTypeSize(GLenum type);
+int VariableRowCount(GLenum type);
+int VariableColumnCount(GLenum type);
+
+int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
+
+int ComputePixelSize(GLenum format, GLenum type);
+GLsizei ComputePitch(GLsizei width, GLenum format, GLenum type, GLint alignment);
+GLsizei ComputeCompressedPitch(GLsizei width, GLenum format);
+GLsizei ComputeCompressedSize(GLsizei width, GLsizei height, GLenum format);
+bool IsCompressed(GLenum format);
+bool IsCubemapTextureTarget(GLenum target);
+bool IsTextureTarget(GLenum target);
+bool CheckTextureFormatType(GLenum format, GLenum type);
+
+bool IsColorRenderable(GLenum internalformat);
+bool IsDepthRenderable(GLenum internalformat);
+bool IsStencilRenderable(GLenum internalformat);
+
+}
+
+namespace es2dx
+{
+
+D3DCMPFUNC ConvertComparison(GLenum comparison);
+D3DCOLOR ConvertColor(gl::Color color);
+D3DBLEND ConvertBlendFunc(GLenum blend);
+D3DBLENDOP ConvertBlendOp(GLenum blendOp);
+D3DSTENCILOP ConvertStencilOp(GLenum stencilOp);
+D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap);
+D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace);
+D3DCUBEMAP_FACES ConvertCubeFace(GLenum cubeFace);
+DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha);
+D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter);
+void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter);
+bool ConvertPrimitiveType(GLenum primitiveType, GLsizei elementCount,
+ D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount);
+D3DFORMAT ConvertRenderbufferFormat(GLenum format);
+D3DMULTISAMPLE_TYPE GetMultisampleTypeFromSamples(GLsizei samples);
+
+}
+
+namespace dx2es
+{
+GLuint GetAlphaSize(D3DFORMAT colorFormat);
+GLuint GetRedSize(D3DFORMAT colorFormat);
+GLuint GetGreenSize(D3DFORMAT colorFormat);
+GLuint GetBlueSize(D3DFORMAT colorFormat);
+GLuint GetDepthSize(D3DFORMAT depthFormat);
+GLuint GetStencilSize(D3DFORMAT stencilFormat);
+
+GLsizei GetSamplesFromMultisampleType(D3DMULTISAMPLE_TYPE type);
+
+GLenum ConvertBackBufferFormat(D3DFORMAT format);
+GLenum ConvertDepthStencilFormat(D3DFORMAT format);
+
+}
+
+std::string getTempPath();
+void writeFile(const char* path, const void* data, size_t size);
+
+#endif // LIBGLESV2_UTILITIES_H
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/vertexconversion.h b/Source/ThirdParty/ANGLE/src/libGLESv2/vertexconversion.h
new file mode 100644
index 000000000..5bb8b8995
--- /dev/null
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/vertexconversion.h
@@ -0,0 +1,208 @@
+//
+// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// vertexconversion.h: A library of vertex conversion classes that can be used to build
+// the FormatConverter objects used by the buffer conversion system.
+
+#ifndef LIBGLESV2_VERTEXCONVERSION_H_
+#define LIBGLESV2_VERTEXCONVERSION_H_
+
+#include <cstddef>
+#include <limits>
+
+#include "libGLESv2/Context.h" // Defines Index
+
+namespace gl
+{
+
+// Conversion types:
+// static const bool identity: true if this is an identity transform, false otherwise
+// static U convert(T): convert a single element from the input type to the output type
+// typedef ... OutputType: the type produced by this conversion
+
+template <class T>
+struct Identity
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return x;
+ }
+};
+
+template <class FromT, class ToT>
+struct Cast
+{
+ static const bool identity = false;
+
+ typedef ToT OutputType;
+
+ static ToT convert(FromT x)
+ {
+ return static_cast<ToT>(x);
+ }
+};
+
+template <class T>
+struct Cast<T, T>
+{
+ static const bool identity = true;
+
+ typedef T OutputType;
+
+ static T convert(T x)
+ {
+ return static_cast<T>(x);
+ }
+};
+
+template <class T>
+struct Normalize
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(T x)
+ {
+ typedef std::numeric_limits<T> NL;
+ float f = static_cast<float>(x);
+
+ if (NL::is_signed)
+ {
+ // const float => VC2008 computes it at compile time
+ // static const float => VC2008 computes it the first time we get here, stores it to memory with static guard and all that.
+ const float divisor = 1.0f/(2*static_cast<float>(NL::max())+1);
+ return (2*f+1)*divisor;
+ }
+ else
+ {
+ return f/NL::max();
+ }
+ }
+};
+
+template <class FromType, std::size_t ScaleBits>
+struct FixedToFloat
+{
+ static const bool identity = false;
+
+ typedef float OutputType;
+
+ static float convert(FromType x)
+ {
+ const float divisor = 1.0f / static_cast<float>(static_cast<FromType>(1) << ScaleBits);
+ return static_cast<float>(x) * divisor;
+ }
+};
+
+// Widen types:
+// static const unsigned int initialWidth: number of components before conversion
+// static const unsigned int finalWidth: number of components after conversion
+
+// Float is supported at any size.
+template <std::size_t N>
+struct NoWiden
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N;
+};
+
+// SHORT, norm-SHORT, norm-UNSIGNED_SHORT are supported but only with 2 or 4 components
+template <std::size_t N>
+struct WidenToEven
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = N+(N&1);
+};
+
+template <std::size_t N>
+struct WidenToFour
+{
+ static const std::size_t initialWidth = N;
+ static const std::size_t finalWidth = 4;
+};
+
+// Most types have 0 and 1 that are just that.
+template <class T>
+struct SimpleDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return static_cast<T>(1); }
+};
+
+// But normalised types only store [0,1] or [-1,1] so 1.0 is represented by the max value.
+template <class T>
+struct NormalizedDefaultValues
+{
+ static T zero() { return static_cast<T>(0); }
+ static T one() { return std::numeric_limits<T>::max(); }
+};
+
+// Converter:
+// static const bool identity: true if this is an identity transform (with no widening)
+// static const std::size_t finalSize: number of bytes per output vertex
+// static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out): convert an array of vertices. Input may be strided, but output will be unstrided.
+
+template <class InT, class WidenRule, class Converter, class DefaultValueRule = SimpleDefaultValues<InT> >
+struct VertexDataConverter
+{
+ typedef typename Converter::OutputType OutputType;
+ typedef InT InputType;
+
+ static const bool identity = (WidenRule::initialWidth == WidenRule::finalWidth) && Converter::identity;
+ static const std::size_t finalSize = WidenRule::finalWidth * sizeof(OutputType);
+
+ static void convertArray(const InputType *in, std::size_t stride, std::size_t n, OutputType *out)
+ {
+ for (std::size_t i = 0; i < n; i++)
+ {
+ const InputType *ein = pointerAddBytes(in, i * stride);
+
+ copyComponent(out, ein, 0, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 1, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 2, static_cast<OutputType>(DefaultValueRule::zero()));
+ copyComponent(out, ein, 3, static_cast<OutputType>(DefaultValueRule::one()));
+
+ out += WidenRule::finalWidth;
+ }
+ }
+
+ static void convertArray(const void *in, std::size_t stride, std::size_t n, void *out)
+ {
+ return convertArray(static_cast<const InputType*>(in), stride, n, static_cast<OutputType*>(out));
+ }
+
+ private:
+ // Advance the given pointer by a number of bytes (not pointed-to elements).
+ template <class T>
+ static T *pointerAddBytes(T *basePtr, std::size_t numBytes)
+ {
+ return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(basePtr) + numBytes);
+ }
+
+ static void copyComponent(OutputType *out, const InputType *in, std::size_t elementindex, OutputType defaultvalue)
+ {
+ if (WidenRule::finalWidth > elementindex)
+ {
+ if (WidenRule::initialWidth > elementindex)
+ {
+ out[elementindex] = Converter::convert(in[elementindex]);
+ }
+ else
+ {
+ out[elementindex] = defaultvalue;
+ }
+ }
+ }
+};
+
+}
+
+#endif // LIBGLESV2_VERTEXCONVERSION_H_
diff --git a/Source/ThirdParty/ChangeLog b/Source/ThirdParty/ChangeLog
new file mode 100644
index 000000000..db565076d
--- /dev/null
+++ b/Source/ThirdParty/ChangeLog
@@ -0,0 +1,236 @@
+2012-01-05 Dan Bernstein <mitz@apple.com>
+
+ Made Debug/Release builds of gtest build only for the active architecture.
+
+ Reviewed by Dave Kilzer.
+
+ * gtest/xcode/Config/DebugProject.xcconfig:
+ * gtest/xcode/Config/ProductionProject.xcconfig:
+ * gtest/xcode/Config/ReleaseProject.xcconfig:
+
+2012-01-04 David Kilzer <ddkilzer@apple.com>
+
+ Remove HEADER_SEARCH_PATHS from Production configurations for gtest
+
+ Reviewed by Mark Rowe.
+
+ * gtest/xcode/gtest.xcodeproj/project.pbxproj: Remove
+ HEADER_SEARCH_PATHS from Production configurations to match
+ changes made for Debug and Release configurations in r104091.
+
+2012-01-04 David Kilzer <ddkilzer@apple.com>
+
+ TestWebKitAPI has issues due to FastMalloc incompatibility
+ <http://webkit.org/b/66521>
+ <rdar://problem/10607911>
+
+ Reviewed by David Levin.
+
+ Original patch by Dmitry Lomov <dslomov@google.com>.
+
+ This patch ensures that gtest uses the FastMalloc new and delete
+ operators that are defined in JavaScriptCore.
+
+ * gtest/README.WebKit: Update with project changes.
+ * gtest/include/gtest/internal/gtest-port.h: Import necessary
+ headers to use FastMalloc in gtest.
+ * gtest/msvc/gtest-md.vcproj: Add include directories to find
+ WTF headers.
+ * gtest/xcode/Config/DebugProject.xcconfig: Define
+ WEBCORE_PRIVATE_HEADERS_DIR for Debug builds.
+ * gtest/xcode/Config/General.xcconfig: Define
+ HEADER_SEARCH_PATHS in terms of WEBCORE_PRIVATE_HEADERS_DIR.
+ * gtest/xcode/Config/ProductionProject.xcconfig: Define
+ WEBCORE_PRIVATE_HEADERS_DIR for Production builds. This
+ overrides the value in ReleaseProject.xcconfig.
+ * gtest/xcode/Config/ReleaseProject.xcconfig: Define
+ WEBCORE_PRIVATE_HEADERS_DIR for Release builds.
+ * gtest/xcode/gtest.xcodeproj/project.pbxproj:
+ - Remove local HEADER_SEARCH_PATHS definitions.
+ - Link to JavaScriptCore.framework when building
+ gtest.framework.
+
+2012-01-03 David Kilzer <ddkilzer@apple.com>
+
+ Add Production configuration to gtest Xcode project
+ <http://webkit.org/b/75153>
+
+ Reviewed by Adam Roben.
+
+ * gtest/README.WebKit: Updated.
+ * gtest/xcode/Config/ProductionProject.xcconfig: Added.
+ * gtest/xcode/gtest.xcodeproj/project.pbxproj:
+ - Added Production configuration based on Release configuration.
+ - Made Production the default configuration.
+
+2011-12-25 Darin Adler <darin@apple.com>
+
+ * gtest/xcode/gtest.xcodeproj: Added property svn:ignore.
+
+2011-11-11 Csaba Osztrogonác <ossy@webkit.org>
+
+ 100,000 !!!
+
+ Reviewed by Zoltan Herczeg.
+
+ * ChangeLog: Point out revision 100,000.
+
+2011-08-25 Alexey Proskuryakov <ap@apple.com>
+
+ Fix build when GCC 4.2 is not installed.
+
+ * gtest/xcode/Config/CompilerVersion.xcconfig: Copied from Source/WebCore/Configurations/CompilerVersion.xcconfig.
+ * gtest/xcode/Config/General.xcconfig:
+ Use the same compiler version as other projects do.
+
+2011-08-19 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r93426.
+ http://trac.webkit.org/changeset/93426
+ https://bugs.webkit.org/show_bug.cgi?id=66607
+
+ Broke the Mac build by not building gtest.framework anymore
+ (Requested by andersca on #webkit).
+
+ * gtest/README.WebKit:
+ * gtest/include/gtest/internal/gtest-port.h:
+ * gtest/msvc/gtest-md.vcproj:
+ * gtest/xcode/Config/General.xcconfig:
+ * gtest/xcode/gtest.xcodeproj/project.pbxproj:
+
+2011-08-18 Dmitry Lomov <dslomov@google.com>
+
+ TestWebKitAPI breaks on Windows due to fast malloc incompatibility.
+ https://bugs.webkit.org/show_bug.cgi?id=66521
+
+ This patch ensures that gtest uses new and delete operators that are defined in JavaScriptCore.
+
+ Reviewed by David Levin.
+
+ * gtest/include/gtest/internal/gtest-port.h:
+ * gtest/msvc/gtest-md.vcproj:
+ * gtest/README.WebKit:
+ * gtest/xcode/Config/General.xcconfig:
+ * gtest/xcode/gtest.xcodeproj/project.pbxproj:
+
+2011-08-09 Mark Rowe <mrowe@apple.com>
+
+ Fix gtest to compile in the release configuration with clang.
+
+ This change was made upstream in r443.
+
+ * gtest/src/gtest.cc:
+
+2011-08-04 Mark Rowe <mrowe@apple.com>
+
+ Future-proof Xcode configuration settings.
+
+ * gtest/xcode/Config/General.xcconfig:
+
+2011-08-03 Dmitry Lomov <dslomov@google.com>
+
+ https://bugs.webkit.org/show_bug.cgi?id=61812
+ TestWebKitApi breaks in release mode due to gtest incompatibility with fast malloc
+
+ Disable fast malloc for offending class (::std::strstream) in gtest.
+ This looks like the most non-intrusive solution.
+
+ Reviewed by David Levin.
+
+ * gtest/include/gtest/internal/gtest-port.h:
+ (testing::internal::StrStream::operator new):
+ (testing::internal::StrStream::operator new[]):
+ (testing::internal::StrStream::operator delete):
+ (testing::internal::StrStream::operator delete[]):
+
+2011-07-05 Adam Barth <abarth@webkit.org>
+
+ Import qunit JavaScript unit testing framework
+ https://bugs.webkit.org/show_bug.cgi?id=63967
+
+ Reviewed by Eric Seidel.
+
+ We're going to use this unit testing framework to test garden-o-matic.
+
+ * qunit: Added.
+
+2011-06-04 Adam Barth <abarth@webkit.org>
+
+ * glu: Added property svn:ignore.
+ - For glu.xcodeproj, which is generated from glu.gyp.
+
+2011-05-24 Stephen White <senorblanco@chromium.org>
+
+ Reviewed by Kenneth Russell.
+
+ Unfork glu sources as much as possible.
+ https://bugs.webkit.org/show_bug.cgi?id=61365
+
+ Restore the glu sources closer to the original version on oss.sgi.com
+ by removing the WebKit-specific include paths, restoring the include
+ order, and renaming the glu* functions via #defines rather than in
+ the source.
+
+ * glu/README.webkit:
+ Update the README to reflect the changes from trunk.
+ * glu/glu.gyp:
+ Add Source/Thirdparty/glu as an include path, so we can remove the
+ hardcoded paths from the source files.
+ * glu/gluos.h:
+ Add #defines to rename the glu entry points to internal_*.
+ * glu/internal_glu.h:
+ * glu/libtess/dict.c:
+ * glu/libtess/geom.c:
+ * glu/libtess/geom.h:
+ * glu/libtess/memalloc.c:
+ * glu/libtess/mesh.c:
+ * glu/libtess/mesh.h:
+ * glu/libtess/normal.c:
+ * glu/libtess/normal.h:
+ * glu/libtess/priorityq-heap.c:
+ * glu/libtess/priorityq-sort.h:
+ * glu/libtess/priorityq.c:
+ * glu/libtess/priorityq.h:
+ * glu/libtess/render.c:
+ * glu/libtess/render.h:
+ * glu/libtess/sweep.c:
+ * glu/libtess/sweep.h:
+ * glu/libtess/tess.c:
+ * glu/libtess/tess.h:
+ * glu/libtess/tessmono.c:
+ Remove WebKit-specific include paths, and internal_ prefixes from glu
+ entry points. Restore include order to original source order.
+
+2011-05-19 Evan Martin <evan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] remove <(library) variable
+ https://bugs.webkit.org/show_bug.cgi?id=61158
+
+ This was for a build experiment; we can just use the correct value now.
+
+ * glu/glu.gyp:
+ * gyp/test/library/src/library.gyp:
+
+2011-05-12 Jeff Miller <jeffm@apple.com>
+
+ Ignore Visual Studio *.user files.
+
+ * gtest/msvc: Added property svn:ignore.
+
+2011-05-12 Adam Roben <aroben@apple.com>
+
+ Windows production build fix
+
+ * gtest/msvc/gtest-md.vcproj: Fix the OutputDirectory and IntermediateDirectory attributes
+ for all configurations.
+
+2011-05-12 Adam Roben <aroben@apple.com>
+
+ A little gtest cleanup after r86287
+
+ * gtest/msvc/gtest-md.vcproj: Added Debug_All and Production configurations to match our
+ other projects. (At some point all the settings should be moved into .vsprops files to match
+ our other projects, too.)
+
diff --git a/Source/ThirdParty/Makefile b/Source/ThirdParty/Makefile
new file mode 100644
index 000000000..d9b8d2a8c
--- /dev/null
+++ b/Source/ThirdParty/Makefile
@@ -0,0 +1,17 @@
+MODULES = ANGLE
+
+all:
+ @for dir in $(MODULES); do ${MAKE} $@ -C $$dir; exit_status=$$?; \
+ if [ $$exit_status -ne 0 ]; then exit $$exit_status; fi; done
+
+debug d development dev develop:
+ @for dir in $(MODULES); do ${MAKE} $@ -C $$dir; exit_status=$$?; \
+ if [ $$exit_status -ne 0 ]; then exit $$exit_status; fi; done
+
+release r deployment dep deploy:
+ @for dir in $(MODULES); do ${MAKE} $@ -C $$dir; exit_status=$$?; \
+ if [ $$exit_status -ne 0 ]; then exit $$exit_status; fi; done
+
+clean:
+ @for dir in $(MODULES); do ${MAKE} $@ -C $$dir; exit_status=$$?; \
+ if [ $$exit_status -ne 0 ]; then exit $$exit_status; fi; done
diff --git a/Source/ThirdParty/Makefile.shared b/Source/ThirdParty/Makefile.shared
new file mode 100644
index 000000000..1c78613f4
--- /dev/null
+++ b/Source/ThirdParty/Makefile.shared
@@ -0,0 +1,2 @@
+SCRIPTS_PATH ?= ../../../Tools/Scripts
+include ../../../Makefile.shared
diff --git a/Source/ThirdParty/glu/LICENSE.txt b/Source/ThirdParty/glu/LICENSE.txt
new file mode 100644
index 000000000..e58ae3880
--- /dev/null
+++ b/Source/ThirdParty/glu/LICENSE.txt
@@ -0,0 +1,31 @@
+SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
+
+Copyright (C) [dates of first publication] Silicon Graphics, Inc. All
+Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice including the dates of first publication
+and either this permission notice or a reference to HYPERLINK
+"http://oss.sgi.com/projects/FreeB/"http://oss.sgi.com/projects/FreeB/
+shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE
+FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of Silicon Graphics,
+Inc. shall not be used in advertising or otherwise to promote the
+sale, use or other dealings in this Software without prior written
+authorization from Silicon Graphics, Inc.
diff --git a/Source/ThirdParty/glu/README.webkit b/Source/ThirdParty/glu/README.webkit
new file mode 100644
index 000000000..e7d4e21d1
--- /dev/null
+++ b/Source/ThirdParty/glu/README.webkit
@@ -0,0 +1,38 @@
+This is a nearly verbatim copy of the GLU tessellator source code from
+SGI's OpenGL Sample Implementation at
+http://oss.sgi.com/projects/ogl-sample/ . Per
+http://oss.sgi.com/projects/FreeB/ , the code is covered under the SGI
+Free Software License B, version 2.0, a copy of which is in
+LICENSE.txt in this directory.
+
+The following changes were made in order to incorporate this code:
+
+ - The addition of a simplified gluos.h to eliminate operating system
+ dependencies. All entry points to the tesselator were prefixed
+ with internal_ via #defines, to avoid symbol collisions with any
+ host OS version of GLU.
+
+ - The removal of inclusion of GL/glu.h and replacement with an
+ include of internal_glu.h.
+
+ - In tess.c, the obsolete entry points gluBeginPolygon,
+ gluNextContour and gluEndPolygon in tess.c were #if 0'd out.
+ Default branches were added to the switch statements in GotoState.
+
+ - In memalloc.h, the include of malloc.h was changed to an include
+ of stdlib.h.
+
+ - In normal.c, an unused variable "w" was removed from
+ __gl_projectPolygon. #if guards were placed around the definition
+ of the unused Normalize function.
+
+ - In priorityq-heap.c, an #include of <limits.h> was added.
+
+ - In sweep.c, IsWindingInside() was given a return value to silence a
+ warning-as-error in release builds.
+
+ - In sweep.c, DoneEdgeDict()'s fixedEdges was wrapped in #indef NDEBUG, to
+ silence a warning-as-error in release builds.
+
+ - In priorityq.c, render.c, and others: the construct "if(1)...else" was
+ replaced with "do{...}while(1)" to silence a warning-as-error in Mac builds.
diff --git a/Source/ThirdParty/glu/glu.gyp b/Source/ThirdParty/glu/glu.gyp
new file mode 100644
index 000000000..b1dac00ef
--- /dev/null
+++ b/Source/ThirdParty/glu/glu.gyp
@@ -0,0 +1,36 @@
+{
+ 'targets': [{
+ 'target_name': 'libtess',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '.',
+ ],
+ 'sources': [
+ 'gluos.h',
+ 'internal_glu.h',
+ 'libtess/dict-list.h',
+ 'libtess/dict.c',
+ 'libtess/dict.h',
+ 'libtess/geom.c',
+ 'libtess/geom.h',
+ 'libtess/memalloc.c',
+ 'libtess/memalloc.h',
+ 'libtess/mesh.c',
+ 'libtess/mesh.h',
+ 'libtess/normal.c',
+ 'libtess/normal.h',
+ 'libtess/priorityq-heap.h',
+ 'libtess/priorityq-sort.h',
+ 'libtess/priorityq.c',
+ 'libtess/priorityq.h',
+ 'libtess/render.c',
+ 'libtess/render.h',
+ 'libtess/sweep.c',
+ 'libtess/sweep.h',
+ 'libtess/tess.c',
+ 'libtess/tess.h',
+ 'libtess/tessmono.c',
+ 'libtess/tessmono.h',
+ ],
+ }],
+}
diff --git a/Source/ThirdParty/glu/gluos.h b/Source/ThirdParty/glu/gluos.h
new file mode 100644
index 000000000..3efc8c748
--- /dev/null
+++ b/Source/ThirdParty/glu/gluos.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GLUOS_H_
+#define GLUOS_H_
+
+// This header provides the minimal definitions needed to compile the
+// GLU tessellator sources.
+#define GLAPIENTRY
+
+typedef unsigned char GLboolean;
+typedef double GLdouble;
+typedef unsigned int GLenum;
+typedef float GLfloat;
+typedef void GLvoid;
+
+#define gluNewTess internal_gluNewTess
+#define gluDeleteTess internal_gluDeleteTess
+#define gluTessProperty internal_gluTessProperty
+#define gluGetTessProperty internal_gluGetTessProperty
+#define gluTessNormal internal_gluTessNormal
+#define gluTessCallback internal_gluTessCallback
+#define gluTessVertex internal_gluTessVertex
+#define gluTessBeginPolygon internal_gluTessBeginPolygon
+#define gluTessBeginContour internal_gluTessBeginContour
+#define gluTessEndContour internal_gluTessEndContour
+#define gluTessEndPolygon internal_gluTessEndPolygon
+
+#undef MIN
+#undef MAX
+
+#endif // GLUOS_H_
diff --git a/Source/ThirdParty/glu/internal_glu.h b/Source/ThirdParty/glu/internal_glu.h
new file mode 100644
index 000000000..02c9cc808
--- /dev/null
+++ b/Source/ThirdParty/glu/internal_glu.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// This header is a skeleton substitute for GL/glu.h which contains
+// only the definitions, constants and function declarations necessary
+// to compile the GLU tessellator.
+
+#ifndef INTERNAL_GLU_H_
+#define INTERNAL_GLU_H_
+
+#include "gluos.h"
+
+/* Primitives */
+#define GL_LINE_LOOP 0x0002
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* ErrorCode */
+#define GLU_INVALID_ENUM 100900
+#define GLU_INVALID_VALUE 100901
+#define GLU_OUT_OF_MEMORY 100902
+
+/* TessCallback */
+#define GLU_TESS_BEGIN 100100
+#define GLU_BEGIN 100100
+#define GLU_TESS_VERTEX 100101
+#define GLU_VERTEX 100101
+#define GLU_TESS_END 100102
+#define GLU_END 100102
+#define GLU_TESS_ERROR 100103
+#define GLU_TESS_EDGE_FLAG 100104
+#define GLU_EDGE_FLAG 100104
+#define GLU_TESS_COMBINE 100105
+#define GLU_TESS_BEGIN_DATA 100106
+#define GLU_TESS_VERTEX_DATA 100107
+#define GLU_TESS_END_DATA 100108
+#define GLU_TESS_ERROR_DATA 100109
+#define GLU_TESS_EDGE_FLAG_DATA 100110
+#define GLU_TESS_COMBINE_DATA 100111
+
+/* TessContour */
+#define GLU_CW 100120
+#define GLU_CCW 100121
+#define GLU_INTERIOR 100122
+#define GLU_EXTERIOR 100123
+#define GLU_UNKNOWN 100124
+
+/* TessProperty */
+#define GLU_TESS_WINDING_RULE 100140
+#define GLU_TESS_BOUNDARY_ONLY 100141
+#define GLU_TESS_TOLERANCE 100142
+
+/* TessError */
+#define GLU_TESS_ERROR1 100151
+#define GLU_TESS_ERROR2 100152
+#define GLU_TESS_ERROR3 100153
+#define GLU_TESS_ERROR4 100154
+#define GLU_TESS_ERROR5 100155
+#define GLU_TESS_ERROR6 100156
+#define GLU_TESS_ERROR7 100157
+#define GLU_TESS_ERROR8 100158
+#define GLU_TESS_MISSING_BEGIN_POLYGON 100151
+#define GLU_TESS_MISSING_BEGIN_CONTOUR 100152
+#define GLU_TESS_MISSING_END_POLYGON 100153
+#define GLU_TESS_MISSING_END_CONTOUR 100154
+#define GLU_TESS_COORD_TOO_LARGE 100155
+#define GLU_TESS_NEED_COMBINE_CALLBACK 100156
+
+/* TessWinding */
+#define GLU_TESS_WINDING_ODD 100130
+#define GLU_TESS_WINDING_NONZERO 100131
+#define GLU_TESS_WINDING_POSITIVE 100132
+#define GLU_TESS_WINDING_NEGATIVE 100133
+#define GLU_TESS_WINDING_ABS_GEQ_TWO 100134
+
+#define GLU_TESS_MAX_COORD 1.0e150
+
+typedef struct GLUtesselator GLUtesselator;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern GLUtesselator * GLAPIENTRY internal_gluNewTess(void);
+extern void GLAPIENTRY internal_gluDeleteTess(GLUtesselator *tess);
+extern void GLAPIENTRY internal_gluTessProperty(GLUtesselator *tess,
+ GLenum which,
+ GLdouble value);
+extern void GLAPIENTRY internal_gluGetTessProperty(GLUtesselator *tess,
+ GLenum which,
+ GLdouble *value);
+extern void GLAPIENTRY internal_gluTessNormal(GLUtesselator *tess,
+ GLdouble x,
+ GLdouble y,
+ GLdouble z);
+extern void GLAPIENTRY internal_gluTessCallback(GLUtesselator *tess,
+ GLenum which,
+ void (GLAPIENTRY *fn)());
+extern void GLAPIENTRY internal_gluTessVertex(GLUtesselator *tess,
+ GLdouble coords[3],
+ void *data);
+extern void GLAPIENTRY internal_gluTessBeginPolygon(GLUtesselator *tess,
+ void *data);
+extern void GLAPIENTRY internal_gluTessBeginContour(GLUtesselator *tess);
+extern void GLAPIENTRY internal_gluTessEndContour(GLUtesselator *tess);
+extern void GLAPIENTRY internal_gluTessEndPolygon(GLUtesselator *tess);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // INTERNAL_GLU_H_
diff --git a/Source/ThirdParty/glu/libtess/GNUmakefile b/Source/ThirdParty/glu/libtess/GNUmakefile
new file mode 100644
index 000000000..0ae859f24
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/GNUmakefile
@@ -0,0 +1,110 @@
+#!gmake
+#
+# License Applicability. Except to the extent portions of this file are
+# made subject to an alternative license as permitted in the SGI Free
+# Software License B, Version 1.1 (the "License"), the contents of this
+# file are subject only to the provisions of the License. You may not use
+# this file except in compliance with the License. You may obtain a copy
+# of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+# Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+#
+# http://oss.sgi.com/projects/FreeB
+#
+# Note that, as provided in the License, the Software is distributed on an
+# "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+# DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+# CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+# PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+#
+# Original Code. The Original Code is: OpenGL Sample Implementation,
+# Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+# Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+# Copyright in any portions created by third parties is as indicated
+# elsewhere herein. All Rights Reserved.
+#
+# Additional Notice Provisions: The application programming interfaces
+# established by SGI in conjunction with the Original Code are The
+# OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+# April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+# 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+# Window System(R) (Version 1.3), released October 19, 1998. This software
+# was created using the OpenGL(R) version 1.2.1 Sample Implementation
+# published by SGI, but has not been independently verified as being
+# compliant with the OpenGL(R) version 1.2.1 Specification.
+#
+# $Date$ $Revision$
+# $Header: //depot/main/gfx/lib/glu/libtess/GNUmakefile#9 $
+
+OBJECT_STYLE = N32
+
+include $(ROOT)/usr/include/make/commondefs
+
+TARGET = libtess.a
+
+TARGETS = $(TARGET)
+
+LCINCS = -I../include
+
+# Compilation flags:
+#
+# -DNDEBUG is for the production code; it removes all assertion checks
+# (note that <assert.h> looks at this symbol).
+#
+# -DNO_MALLOPT uses regular malloc instead of the mallopt() version.
+# ***** Unless you use this flag, you must use "-lmalloc" to link
+# ***** your application!
+#
+# -DMEMORY_DEBUG turns on the M_DEBUG option of mallopt; this can
+# increase the running time a LOT.
+#
+# -DGLU_TESS_API_FLOAT compiles a single-precision version of the library.
+#
+# -float prevents automatic promotion to double precision; this will produce
+# faster code when compiled with -DGLU_TESS_API_FLOAT.
+#
+# -DNO_BRANCH_CONDITIONS uses & and | instead of && and || on a couple
+# of heavily-used tests (VertEq and VertLeq); some compilers can generate
+# better code with these (use special instructions to avoid branching).
+#
+# -DFOR_TRITE_TEST_PROGRAM is *only* for use with the test program called
+# "trite". It uses some variables which are defined by the test program,
+# so you won't be able to link it with anything else.
+
+HFILES = \
+ dict.h \
+ dict-list.h \
+ geom.h \
+ memalloc.h \
+ mesh.h \
+ normal.h \
+ priorityq-heap.h \
+ priorityq-heap.c \
+ priorityq-sort.h \
+ priorityq.h \
+ render.h \
+ sweep.h \
+ tess.h \
+ tessmono.h \
+ $(NULL)
+
+CFILES = \
+ dict.c \
+ geom.c \
+ memalloc.c \
+ mesh.c \
+ normal.c \
+ priorityq.c \
+ render.c \
+ sweep.c \
+ tess.c \
+ tessmono.c \
+ $(NULL)
+
+default libs libs_install install: $(TARGET)
+
+headers headers_install apps:
+
+$(TARGET): $(OBJECTS)
+ $(AR) crl $@ $(OBJECTS);
+
+include $(COMMONRULES)
diff --git a/Source/ThirdParty/glu/libtess/Imakefile b/Source/ThirdParty/glu/libtess/Imakefile
new file mode 100644
index 000000000..fb99ce22e
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/Imakefile
@@ -0,0 +1,61 @@
+XCOMM License Applicability. Except to the extent portions of this file are
+XCOMM made subject to an alternative license as permitted in the SGI Free
+XCOMM Software License B, Version 1.1 (the "License"), the contents of this
+XCOMM file are subject only to the provisions of the License. You may not use
+XCOMM this file except in compliance with the License. You may obtain a copy
+XCOMM of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+XCOMM Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+XCOMM
+XCOMM http://oss.sgi.com/projects/FreeB
+XCOMM
+XCOMM Note that, as provided in the License, the Software is distributed on an
+XCOMM "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+XCOMM DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+XCOMM CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+XCOMM PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+XCOMM
+XCOMM Original Code. The Original Code is: OpenGL Sample Implementation,
+XCOMM Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+XCOMM Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+XCOMM Copyright in any portions created by third parties is as indicated
+XCOMM elsewhere herein. All Rights Reserved.
+XCOMM
+XCOMM Additional Notice Provisions: The application programming interfaces
+XCOMM established by SGI in conjunction with the Original Code are The
+XCOMM OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+XCOMM April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+XCOMM 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+XCOMM Window System(R) (Version 1.3), released October 19, 1998. This software
+XCOMM was created using the OpenGL(R) version 1.2.1 Sample Implementation
+XCOMM published by SGI, but has not been independently verified as being
+XCOMM compliant with the OpenGL(R) version 1.2.1 Specification.
+XCOMM
+
+#include <Library.tmpl>
+
+OBJS = \
+ dict.o \
+ geom.o \
+ memalloc.o \
+ mesh.o \
+ normal.o \
+ priorityq.o \
+ render.o \
+ sweep.o \
+ tess.o \
+ tessmono.o
+
+INCLUDES = \
+ -I../include \
+ -I$(TOP)/include \
+ -I$(TOP)/include/GL
+
+DEFINES = \
+ -DNDEBUG
+
+NormalLibraryObjectRule()
+
+NormalLibraryTarget(tess, $(OBJS))
+
+DependTarget()
+CleanTarget()
diff --git a/Source/ThirdParty/glu/libtess/README b/Source/ThirdParty/glu/libtess/README
new file mode 100644
index 000000000..59f4ff2ef
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/README
@@ -0,0 +1,447 @@
+/*
+** $Header: /cvs/projects/ogl-sample/main/gfx/lib/glu/libtess/README,v 1.1 2000/04/26 05:53:59 ljp Exp $
+*/
+
+General Polygon Tesselation
+---------------------------
+
+ This note describes a tesselator for polygons consisting of one or
+ more closed contours. It is backward-compatible with the current
+ OpenGL Utilities tesselator, and is intended to replace it. Here is
+ a summary of the major differences:
+
+ - input contours can be intersecting, self-intersecting, or degenerate.
+
+ - supports a choice of several winding rules for determining which parts
+ of the polygon are on the "interior". This makes it possible to do
+ CSG operations on polygons.
+
+ - boundary extraction: instead of tesselating the polygon, returns a
+ set of closed contours which separate the interior from the exterior.
+
+ - returns the output as a small number of triangle fans and strips,
+ rather than a list of independent triangles (when possible).
+
+ - output is available as an explicit mesh (a quad-edge structure),
+ in addition to the normal callback interface.
+
+ - the algorithm used is extremely robust.
+
+
+The interface
+-------------
+
+ The tesselator state is maintained in a "tesselator object".
+ These are allocated and destroyed using
+
+ GLUtesselator *gluNewTess( void );
+ void gluDeleteTess( GLUtesselator *tess );
+
+ Several tesselator objects may be used simultaneously.
+
+ Inputs
+ ------
+
+ The input contours are specified with the following routines:
+
+ void gluTessBeginPolygon( GLUtesselator *tess );
+ void gluTessBeginContour( GLUtesselator *tess );
+ void gluTessVertex( GLUtesselator *tess, GLUcoord coords[3], void *data );
+ void gluTessEndContour( GLUtesselator *tess );
+ void gluTessEndPolygon( GLUtesselator *tess );
+
+ Within each BeginPolygon/EndPolygon pair, there can be zero or more
+ calls to BeginContour/EndContour. Within each contour, there are zero
+ or more calls to gluTessVertex(). The vertices specify a closed
+ contour (the last vertex of each contour is automatically linked to
+ the first).
+
+ "coords" give the coordinates of the vertex in 3-space. For useful
+ results, all vertices should lie in some plane, since the vertices
+ are projected onto a plane before tesselation. "data" is a pointer
+ to a user-defined vertex structure, which typically contains other
+ information such as color, texture coordinates, normal, etc. It is
+ used to refer to the vertex during rendering.
+
+ The library can be compiled in single- or double-precision; the type
+ GLUcoord represents either "float" or "double" accordingly. The GLU
+ version will be available in double-precision only. Compile with
+ GLU_TESS_API_FLOAT defined to get the single-precision version.
+
+ When EndPolygon is called, the tesselation algorithm determines
+ which regions are interior to the given contours, according to one
+ of several "winding rules" described below. The interior regions
+ are then tesselated, and the output is provided as callbacks.
+
+
+ Rendering Callbacks
+ -------------------
+
+ Callbacks are specified by the client using
+
+ void gluTessCallback( GLUtesselator *tess, GLenum which, void (*fn)());
+
+ If "fn" is NULL, any previously defined callback is discarded.
+
+ The callbacks used to provide output are: /* which == */
+
+ void begin( GLenum type ); /* GLU_TESS_BEGIN */
+ void edgeFlag( GLboolean flag ); /* GLU_TESS_EDGE_FLAG */
+ void vertex( void *data ); /* GLU_TESS_VERTEX */
+ void end( void ); /* GLU_TESS_END */
+
+ Any of the callbacks may be left undefined; if so, the corresponding
+ information will not be supplied during rendering.
+
+ The "begin" callback indicates the start of a primitive; type is one
+ of GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES (but see the
+ notes on "boundary extraction" below).
+
+ It is followed by any number of "vertex" callbacks, which supply the
+ vertices in the same order as expected by the corresponding glBegin()
+ call. After the last vertex of a given primitive, there is a callback
+ to "end".
+
+ If the "edgeFlag" callback is provided, no triangle fans or strips
+ will be used. When edgeFlag is called, if "flag" is GL_TRUE then each
+ vertex which follows begins an edge which lies on the polygon boundary
+ (ie. an edge which separates an interior region from an exterior one).
+ If "flag" is GL_FALSE, each vertex which follows begins an edge which lies
+ in the polygon interior. "edgeFlag" will be called before the first
+ call to "vertex".
+
+ Other Callbacks
+ ---------------
+
+ void mesh( GLUmesh *mesh ); /* GLU_TESS_MESH */
+
+ - Returns an explicit mesh, represented using the quad-edge structure
+ (Guibas/Stolfi '85). Other implementations of this interface might
+ use a different mesh structure, so this is available only only as an
+ SGI extension. When the mesh is no longer needed, it should be freed
+ using
+
+ void gluDeleteMesh( GLUmesh *mesh );
+
+ There is a brief description of this data structure in the include
+ file "mesh.h". For the full details, see L. Guibas and J. Stolfi,
+ Primitives for the manipulation of general subdivisions and the
+ computation of Voronoi diagrams, ACM Transactions on Graphics,
+ 4(2):74-123, April 1985. For an introduction, see the course notes
+ for CS348a, "Mathematical Foundations of Computer Graphics",
+ available at the Stanford bookstore (and taught during the fall
+ quarter).
+
+ void error( GLenum errno ); /* GLU_TESS_ERROR */
+
+ - errno is one of GLU_TESS_MISSING_BEGIN_POLYGON,
+ GLU_TESS_MISSING_END_POLYGON,
+ GLU_TESS_MISSING_BEGIN_CONTOUR,
+ GLU_TESS_MISSING_END_CONTOUR,
+ GLU_TESS_COORD_TOO_LARGE,
+ GLU_TESS_NEED_COMBINE_CALLBACK
+
+ The first four are obvious. The interface recovers from these
+ errors by inserting the missing call(s).
+
+ GLU_TESS_COORD_TOO_LARGE says that some vertex coordinate exceeded
+ the predefined constant GLU_TESS_MAX_COORD in absolute value, and
+ that the value has been clamped. (Coordinate values must be small
+ enough so that two can be multiplied together without overflow.)
+
+ GLU_TESS_NEED_COMBINE_CALLBACK says that the algorithm detected an
+ intersection between two edges in the input data, and the "combine"
+ callback (below) was not provided. No output will be generated.
+
+
+ void combine( GLUcoord coords[3], void *data[4], /* GLU_TESS_COMBINE */
+ GLUcoord weight[4], void **outData );
+
+ - When the algorithm detects an intersection, or wishes to merge
+ features, it needs to create a new vertex. The vertex is defined
+ as a linear combination of up to 4 existing vertices, referenced
+ by data[0..3]. The coefficients of the linear combination are
+ given by weight[0..3]; these weights always sum to 1.0. All vertex
+ pointers are valid even when some of the weights are zero.
+ "coords" gives the location of the new vertex.
+
+ The user must allocate another vertex, interpolate parameters
+ using "data" and "weights", and return the new vertex pointer in
+ "outData". This handle is supplied during rendering callbacks.
+ For example, if the polygon lies in an arbitrary plane in 3-space,
+ and we associate a color with each vertex, the combine callback might
+ look like this:
+
+ void myCombine( GLUcoord coords[3], VERTEX *d[4],
+ GLUcoord w[4], VERTEX **dataOut )
+ {
+ VERTEX *new = new_vertex();
+
+ new->x = coords[0];
+ new->y = coords[1];
+ new->z = coords[2];
+ new->r = w[0]*d[0]->r + w[1]*d[1]->r + w[2]*d[2]->r + w[3]*d[3]->r;
+ new->g = w[0]*d[0]->g + w[1]*d[1]->g + w[2]*d[2]->g + w[3]*d[3]->g;
+ new->b = w[0]*d[0]->b + w[1]*d[1]->b + w[2]*d[2]->b + w[3]*d[3]->b;
+ new->a = w[0]*d[0]->a + w[1]*d[1]->a + w[2]*d[2]->a + w[3]*d[3]->a;
+ *dataOut = new;
+ }
+
+ If the algorithm detects an intersection, then the "combine" callback
+ must be defined, and must write a non-NULL pointer into "dataOut".
+ Otherwise the GLU_TESS_NEED_COMBINE_CALLBACK error occurs, and no
+ output is generated. This is the only error that can occur during
+ tesselation and rendering.
+
+
+ Control over Tesselation
+ ------------------------
+
+ void gluTessProperty( GLUtesselator *tess, GLenum which, GLUcoord value );
+
+ Properties defined:
+
+ - GLU_TESS_WINDING_RULE. Possible values:
+
+ GLU_TESS_WINDING_ODD
+ GLU_TESS_WINDING_NONZERO
+ GLU_TESS_WINDING_POSITIVE
+ GLU_TESS_WINDING_NEGATIVE
+ GLU_TESS_WINDING_ABS_GEQ_TWO
+
+ The input contours parition the plane into regions. A winding
+ rule determines which of these regions are inside the polygon.
+
+ For a single contour C, the winding number of a point x is simply
+ the signed number of revolutions we make around x as we travel
+ once around C (where CCW is positive). When there are several
+ contours, the individual winding numbers are summed. This
+ procedure associates a signed integer value with each point x in
+ the plane. Note that the winding number is the same for all
+ points in a single region.
+
+ The winding rule classifies a region as "inside" if its winding
+ number belongs to the chosen category (odd, nonzero, positive,
+ negative, or absolute value of at least two). The current GLU
+ tesselator implements the "odd" rule. The "nonzero" rule is another
+ common way to define the interior. The other three rules are
+ useful for polygon CSG operations (see below).
+
+ - GLU_TESS_BOUNDARY_ONLY. Values: TRUE (non-zero) or FALSE (zero).
+
+ If TRUE, returns a set of closed contours which separate the
+ polygon interior and exterior (rather than a tesselation).
+ Exterior contours are oriented CCW with respect to the normal,
+ interior contours are oriented CW. The GLU_TESS_BEGIN callback
+ uses the type GL_LINE_LOOP for each contour.
+
+ - GLU_TESS_TOLERANCE. Value: a real number between 0.0 and 1.0.
+
+ This specifies a tolerance for merging features to reduce the size
+ of the output. For example, two vertices which are very close to
+ each other might be replaced by a single vertex. The tolerance
+ is multiplied by the largest coordinate magnitude of any input vertex;
+ this specifies the maximum distance that any feature can move as the
+ result of a single merge operation. If a single feature takes part
+ in several merge operations, the total distance moved could be larger.
+
+ Feature merging is completely optional; the tolerance is only a hint.
+ The implementation is free to merge in some cases and not in others,
+ or to never merge features at all. The default tolerance is zero.
+
+ The current implementation merges vertices only if they are exactly
+ coincident, regardless of the current tolerance. A vertex is
+ spliced into an edge only if the implementation is unable to
+ distinguish which side of the edge the vertex lies on.
+ Two edges are merged only when both endpoints are identical.
+
+
+ void gluTessNormal( GLUtesselator *tess,
+ GLUcoord x, GLUcoord y, GLUcoord z )
+
+ - Lets the user supply the polygon normal, if known. All input data
+ is projected into a plane perpendicular to the normal before
+ tesselation. All output triangles are oriented CCW with
+ respect to the normal (CW orientation can be obtained by
+ reversing the sign of the supplied normal). For example, if
+ you know that all polygons lie in the x-y plane, call
+ "gluTessNormal(tess, 0.0, 0.0, 1.0)" before rendering any polygons.
+
+ - If the supplied normal is (0,0,0) (the default value), the
+ normal is determined as follows. The direction of the normal,
+ up to its sign, is found by fitting a plane to the vertices,
+ without regard to how the vertices are connected. It is
+ expected that the input data lies approximately in plane;
+ otherwise projection perpendicular to the computed normal may
+ substantially change the geometry. The sign of the normal is
+ chosen so that the sum of the signed areas of all input contours
+ is non-negative (where a CCW contour has positive area).
+
+ - The supplied normal persists until it is changed by another
+ call to gluTessNormal.
+
+
+ Backward compatibility with the GLU tesselator
+ ----------------------------------------------
+
+ The preferred interface is the one described above. The following
+ routines are obsolete, and are provided only for backward compatibility:
+
+ typedef GLUtesselator GLUtriangulatorObj; /* obsolete name */
+
+ void gluBeginPolygon( GLUtesselator *tess );
+ void gluNextContour( GLUtesselator *tess, GLenum type );
+ void gluEndPolygon( GLUtesselator *tess );
+
+ "type" is one of GLU_EXTERIOR, GLU_INTERIOR, GLU_CCW, GLU_CW, or
+ GLU_UNKNOWN. It is ignored by the current GLU tesselator.
+
+ GLU_BEGIN, GLU_VERTEX, GLU_END, GLU_ERROR, and GLU_EDGE_FLAG are defined
+ as synonyms for GLU_TESS_BEGIN, GLU_TESS_VERTEX, GLU_TESS_END,
+ GLU_TESS_ERROR, and GLU_TESS_EDGE_FLAG.
+
+
+Polygon CSG operations
+----------------------
+
+ The features of the tesselator make it easy to find the union, difference,
+ or intersection of several polygons.
+
+ First, assume that each polygon is defined so that the winding number
+ is 0 for each exterior region, and 1 for each interior region. Under
+ this model, CCW contours define the outer boundary of the polygon, and
+ CW contours define holes. Contours may be nested, but a nested
+ contour must be oriented oppositely from the contour that contains it.
+
+ If the original polygons do not satisfy this description, they can be
+ converted to this form by first running the tesselator with the
+ GLU_TESS_BOUNDARY_ONLY property turned on. This returns a list of
+ contours satisfying the restriction above. By allocating two
+ tesselator objects, the callbacks from one tesselator can be fed
+ directly to the input of another.
+
+ Given two or more polygons of the form above, CSG operations can be
+ implemented as follows:
+
+ Union
+ Draw all the input contours as a single polygon. The winding number
+ of each resulting region is the number of original polygons
+ which cover it. The union can be extracted using the
+ GLU_TESS_WINDING_NONZERO or GLU_TESS_WINDING_POSITIVE winding rules.
+ Note that with the nonzero rule, we would get the same result if
+ all contour orientations were reversed.
+
+ Intersection (two polygons at a time only)
+ Draw a single polygon using the contours from both input polygons.
+ Extract the result using GLU_TESS_WINDING_ABS_GEQ_TWO. (Since this
+ winding rule looks at the absolute value, reversing all contour
+ orientations does not change the result.)
+
+ Difference
+
+ Suppose we want to compute A \ (B union C union D). Draw a single
+ polygon consisting of the unmodified contours from A, followed by
+ the contours of B,C,D with the vertex order reversed (this changes
+ the winding number of the interior regions to -1). To extract the
+ result, use the GLU_TESS_WINDING_POSITIVE rule.
+
+ If B,C,D are the result of a GLU_TESS_BOUNDARY_ONLY call, an
+ alternative to reversing the vertex order is to reverse the sign of
+ the supplied normal. For example in the x-y plane, call
+ gluTessNormal( tess, 0.0, 0.0, -1.0 ).
+
+
+Performance
+-----------
+
+ The tesselator is not intended for immediate-mode rendering; when
+ possible the output should be cached in a user structure or display
+ list. General polygon tesselation is an inherently difficult problem,
+ especially given the goal of extreme robustness.
+
+ The implementation makes an effort to output a small number of fans
+ and strips; this should improve the rendering performance when the
+ output is used in a display list.
+
+ Single-contour input polygons are first tested to see whether they can
+ be rendered as a triangle fan with respect to the first vertex (to
+ avoid running the full decomposition algorithm on convex polygons).
+ Non-convex polygons may be rendered by this "fast path" as well, if
+ the algorithm gets lucky in its choice of a starting vertex.
+
+ For best performance follow these guidelines:
+
+ - supply the polygon normal, if available, using gluTessNormal().
+ This represents about 10% of the computation time. For example,
+ if all polygons lie in the x-y plane, use gluTessNormal(tess,0,0,1).
+
+ - render many polygons using the same tesselator object, rather than
+ allocating a new tesselator for each one. (In a multi-threaded,
+ multi-processor environment you may get better performance using
+ several tesselators.)
+
+
+Comparison with the GLU tesselator
+----------------------------------
+
+ On polygons which make it through the "fast path", the tesselator is
+ 3 to 5 times faster than the GLU tesselator.
+
+ On polygons which don't make it through the fast path (but which don't
+ have self-intersections or degeneracies), it is about 2 times slower.
+
+ On polygons with self-intersections or degeneraces, there is nothing
+ to compare against.
+
+ The new tesselator generates many more fans and strips, reducing the
+ number of vertices that need to be sent to the hardware.
+
+ Key to the statistics:
+
+ vert number of input vertices on all contours
+ cntr number of input contours
+ tri number of triangles in all output primitives
+ strip number of triangle strips
+ fan number of triangle fans
+ ind number of independent triangles
+ ms number of milliseconds for tesselation
+ (on a 150MHz R4400 Indy)
+
+ Convex polygon examples:
+
+New: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.0459 ms
+Old: 3 vert, 1 cntr, 1 tri, 0 strip, 0 fan, 1 ind, 0.149 ms
+New: 4 vert, 1 cntr, 2 tri, 0 strip, 1 fan, 0 ind, 0.0459 ms
+Old: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.161 ms
+New: 36 vert, 1 cntr, 34 tri, 0 strip, 1 fan, 0 ind, 0.153 ms
+Old: 36 vert, 1 cntr, 34 tri, 0 strip, 0 fan, 34 ind, 0.621 ms
+
+ Concave single-contour polygons:
+
+New: 5 vert, 1 cntr, 3 tri, 0 strip, 1 fan, 0 ind, 0.052 ms
+Old: 5 vert, 1 cntr, 3 tri, 0 strip, 0 fan, 3 ind, 0.252 ms
+New: 19 vert, 1 cntr, 17 tri, 2 strip, 2 fan, 1 ind, 0.911 ms
+Old: 19 vert, 1 cntr, 17 tri, 0 strip, 0 fan, 17 ind, 0.529 ms
+New: 151 vert, 1 cntr, 149 tri, 13 strip, 18 fan, 3 ind, 6.82 ms
+Old: 151 vert, 1 cntr, 149 tri, 0 strip, 3 fan, 143 ind, 2.7 ms
+New: 574 vert, 1 cntr, 572 tri, 59 strip, 54 fan, 11 ind, 26.6 ms
+Old: 574 vert, 1 cntr, 572 tri, 0 strip, 31 fan, 499 ind, 12.4 ms
+
+ Multiple contours, but no intersections:
+
+New: 7 vert, 2 cntr, 7 tri, 1 strip, 0 fan, 0 ind, 0.527 ms
+Old: 7 vert, 2 cntr, 7 tri, 0 strip, 0 fan, 7 ind, 0.274 ms
+New: 81 vert, 6 cntr, 89 tri, 9 strip, 7 fan, 6 ind, 3.88 ms
+Old: 81 vert, 6 cntr, 89 tri, 0 strip, 13 fan, 61 ind, 2.2 ms
+New: 391 vert, 19 cntr, 413 tri, 37 strip, 32 fan, 26 ind, 20.2 ms
+Old: 391 vert, 19 cntr, 413 tri, 0 strip, 25 fan, 363 ind, 8.68 ms
+
+ Self-intersecting and degenerate examples:
+
+Bowtie: 4 vert, 1 cntr, 2 tri, 0 strip, 0 fan, 2 ind, 0.483 ms
+Star: 5 vert, 1 cntr, 5 tri, 0 strip, 0 fan, 5 ind, 0.91 ms
+Random: 24 vert, 7 cntr, 46 tri, 2 strip, 12 fan, 7 ind, 5.32 ms
+Font: 333 vert, 2 cntr, 331 tri, 32 strip, 16 fan, 3 ind, 14.1 ms
+: 167 vert, 35 cntr, 254 tri, 8 strip, 56 fan, 52 ind, 46.3 ms
+: 78 vert, 1 cntr, 2675 tri, 148 strip, 207 fan, 180 ind, 243 ms
+: 12480 vert, 2 cntr, 12478 tri, 736 strip,1275 fan, 5 ind, 1010 ms
diff --git a/Source/ThirdParty/glu/libtess/alg-outline b/Source/ThirdParty/glu/libtess/alg-outline
new file mode 100644
index 000000000..91ed7f32c
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/alg-outline
@@ -0,0 +1,229 @@
+/*
+** $Header: /cvs/projects/ogl-sample/main/gfx/lib/glu/libtess/alg-outline,v 1.1 2000/04/26 05:53:59 ljp Exp $
+*/
+
+This is only a very brief overview. There is quite a bit of
+additional documentation in the source code itself.
+
+
+Goals of robust tesselation
+---------------------------
+
+The tesselation algorithm is fundamentally a 2D algorithm. We
+initially project all data into a plane; our goal is to robustly
+tesselate the projected data. The same topological tesselation is
+then applied to the input data.
+
+Topologically, the output should always be a tesselation. If the
+input is even slightly non-planar, then some triangles will
+necessarily be back-facing when viewed from some angles, but the goal
+is to minimize this effect.
+
+The algorithm needs some capability of cleaning up the input data as
+well as the numerical errors in its own calculations. One way to do
+this is to specify a tolerance as defined above, and clean up the
+input and output during the line sweep process. At the very least,
+the algorithm must handle coincident vertices, vertices incident to an
+edge, and coincident edges.
+
+
+Phases of the algorithm
+-----------------------
+
+1. Find the polygon normal N.
+2. Project the vertex data onto a plane. It does not need to be
+ perpendicular to the normal, eg. we can project onto the plane
+ perpendicular to the coordinate axis whose dot product with N
+ is largest.
+3. Using a line-sweep algorithm, partition the plane into x-monotone
+ regions. Any vertical line intersects an x-monotone region in
+ at most one interval.
+4. Triangulate the x-monotone regions.
+5. Group the triangles into strips and fans.
+
+
+Finding the normal vector
+-------------------------
+
+A common way to find a polygon normal is to compute the signed area
+when the polygon is projected along the three coordinate axes. We
+can't do this, since contours can have zero area without being
+degenerate (eg. a bowtie).
+
+We fit a plane to the vertex data, ignoring how they are connected
+into contours. Ideally this would be a least-squares fit; however for
+our purpose the accuracy of the normal is not important. Instead we
+find three vertices which are widely separated, and compute the normal
+to the triangle they form. The vertices are chosen so that the
+triangle has an area at least 1/sqrt(3) times the largest area of any
+triangle formed using the input vertices.
+
+The contours do affect the orientation of the normal; after computing
+the normal, we check that the sum of the signed contour areas is
+non-negative, and reverse the normal if necessary.
+
+
+Projecting the vertices
+-----------------------
+
+We project the vertices onto a plane perpendicular to one of the three
+coordinate axes. This helps numerical accuracy by removing a
+transformation step between the original input data and the data
+processed by the algorithm. The projection also compresses the input
+data; the 2D distance between vertices after projection may be smaller
+than the original 2D distance. However by choosing the coordinate
+axis whose dot product with the normal is greatest, the compression
+factor is at most 1/sqrt(3).
+
+Even though the *accuracy* of the normal is not that important (since
+we are projecting perpendicular to a coordinate axis anyway), the
+*robustness* of the computation is important. For example, if there
+are many vertices which lie almost along a line, and one vertex V
+which is well-separated from the line, then our normal computation
+should involve V otherwise the results will be garbage.
+
+The advantage of projecting perpendicular to the polygon normal is
+that computed intersection points will be as close as possible to
+their ideal locations. To get this behavior, define TRUE_PROJECT.
+
+
+The Line Sweep
+--------------
+
+There are three data structures: the mesh, the event queue, and the
+edge dictionary.
+
+The mesh is a "quad-edge" data structure which records the topology of
+the current decomposition; for details see the include file "mesh.h".
+
+The event queue simply holds all vertices (both original and computed
+ones), organized so that we can quickly extract the vertex with the
+minimum x-coord (and among those, the one with the minimum y-coord).
+
+The edge dictionary describes the current intersection of the sweep
+line with the regions of the polygon. This is just an ordering of the
+edges which intersect the sweep line, sorted by their current order of
+intersection. For each pair of edges, we store some information about
+the monotone region between them -- these are call "active regions"
+(since they are crossed by the current sweep line).
+
+The basic algorithm is to sweep from left to right, processing each
+vertex. The processed portion of the mesh (left of the sweep line) is
+a planar decomposition. As we cross each vertex, we update the mesh
+and the edge dictionary, then we check any newly adjacent pairs of
+edges to see if they intersect.
+
+A vertex can have any number of edges. Vertices with many edges can
+be created as vertices are merged and intersection points are
+computed. For unprocessed vertices (right of the sweep line), these
+edges are in no particular order around the vertex; for processed
+vertices, the topological ordering should match the geometric ordering.
+
+The vertex processing happens in two phases: first we process are the
+left-going edges (all these edges are currently in the edge
+dictionary). This involves:
+
+ - deleting the left-going edges from the dictionary;
+ - relinking the mesh if necessary, so that the order of these edges around
+ the event vertex matches the order in the dictionary;
+ - marking any terminated regions (regions which lie between two left-going
+ edges) as either "inside" or "outside" according to their winding number.
+
+When there are no left-going edges, and the event vertex is in an
+"interior" region, we need to add an edge (to split the region into
+monotone pieces). To do this we simply join the event vertex to the
+rightmost left endpoint of the upper or lower edge of the containing
+region.
+
+Then we process the right-going edges. This involves:
+
+ - inserting the edges in the edge dictionary;
+ - computing the winding number of any newly created active regions.
+ We can compute this incrementally using the winding of each edge
+ that we cross as we walk through the dictionary.
+ - relinking the mesh if necessary, so that the order of these edges around
+ the event vertex matches the order in the dictionary;
+ - checking any newly adjacent edges for intersection and/or merging.
+
+If there are no right-going edges, again we need to add one to split
+the containing region into monotone pieces. In our case it is most
+convenient to add an edge to the leftmost right endpoint of either
+containing edge; however we may need to change this later (see the
+code for details).
+
+
+Invariants
+----------
+
+These are the most important invariants maintained during the sweep.
+We define a function VertLeq(v1,v2) which defines the order in which
+vertices cross the sweep line, and a function EdgeLeq(e1,e2; loc)
+which says whether e1 is below e2 at the sweep event location "loc".
+This function is defined only at sweep event locations which lie
+between the rightmost left endpoint of {e1,e2}, and the leftmost right
+endpoint of {e1,e2}.
+
+Invariants for the Edge Dictionary.
+
+ - Each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+ at any valid location of the sweep event.
+ - If EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+ share a common endpoint.
+ - For each e in the dictionary, e->Dst has been processed but not e->Org.
+ - Each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
+ where "event" is the current sweep line event.
+ - No edge e has zero length.
+ - No two edges have identical left and right endpoints.
+
+Invariants for the Mesh (the processed portion).
+
+ - The portion of the mesh left of the sweep line is a planar graph,
+ ie. there is *some* way to embed it in the plane.
+ - No processed edge has zero length.
+ - No two processed vertices have identical coordinates.
+ - Each "inside" region is monotone, ie. can be broken into two chains
+ of monotonically increasing vertices according to VertLeq(v1,v2)
+ - a non-invariant: these chains may intersect (slightly) due to
+ numerical errors, but this does not affect the algorithm's operation.
+
+Invariants for the Sweep.
+
+ - If a vertex has any left-going edges, then these must be in the edge
+ dictionary at the time the vertex is processed.
+ - If an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+ by ConnectRightVertex), then it is the only right-going edge from
+ its associated vertex. (This says that these edges exist only
+ when it is necessary.)
+
+
+Robustness
+----------
+
+The key to the robustness of the algorithm is maintaining the
+invariants above, especially the correct ordering of the edge
+dictionary. We achieve this by:
+
+ 1. Writing the numerical computations for maximum precision rather
+ than maximum speed.
+
+ 2. Making no assumptions at all about the results of the edge
+ intersection calculations -- for sufficiently degenerate inputs,
+ the computed location is not much better than a random number.
+
+ 3. When numerical errors violate the invariants, restore them
+ by making *topological* changes when necessary (ie. relinking
+ the mesh structure).
+
+
+Triangulation and Grouping
+--------------------------
+
+We finish the line sweep before doing any triangulation. This is
+because even after a monotone region is complete, there can be further
+changes to its vertex data because of further vertex merging.
+
+After triangulating all monotone regions, we want to group the
+triangles into fans and strips. We do this using a greedy approach.
+The triangulation itself is not optimized to reduce the number of
+primitives; we just try to get a reasonable decomposition of the
+computed triangulation.
diff --git a/Source/ThirdParty/glu/libtess/dict-list.h b/Source/ThirdParty/glu/libtess/dict-list.h
new file mode 100644
index 000000000..9c67c49f3
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/dict-list.h
@@ -0,0 +1,107 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/dict-list.h#5 $
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey DictListKey
+#define Dict DictList
+#define DictNode DictListNode
+
+#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
+
+#define dictKey(n) __gl_dictListKey(n)
+#define dictSucc(n) __gl_dictListSucc(n)
+#define dictPred(n) __gl_dictListPred(n)
+#define dictMin(d) __gl_dictListMin(d)
+#define dictMax(d) __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict *dictNewDict(
+ void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) );
+
+void dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key. If there is no such key, returns a node whose
+ * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode *dictSearch( Dict *dict, DictKey key );
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void dictDelete( Dict *dict, DictNode *node );
+
+#define __gl_dictListKey(n) ((n)->key)
+#define __gl_dictListSucc(n) ((n)->next)
+#define __gl_dictListPred(n) ((n)->prev)
+#define __gl_dictListMin(d) ((d)->head.next)
+#define __gl_dictListMax(d) ((d)->head.prev)
+#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+ DictKey key;
+ DictNode *next;
+ DictNode *prev;
+};
+
+struct Dict {
+ DictNode head;
+ void *frame;
+ int (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/dict.c b/Source/ThirdParty/glu/libtess/dict.c
new file mode 100644
index 000000000..e149fd549
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/dict.c
@@ -0,0 +1,117 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/dict.c#5 $
+*/
+
+#include <stddef.h>
+#include "dict-list.h"
+#include "memalloc.h"
+
+/* really __gl_dictListNewDict */
+Dict *dictNewDict( void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) )
+{
+ Dict *dict = (Dict *) memAlloc( sizeof( Dict ));
+ DictNode *head;
+
+ if (dict == NULL) return NULL;
+
+ head = &dict->head;
+
+ head->key = NULL;
+ head->next = head;
+ head->prev = head;
+
+ dict->frame = frame;
+ dict->leq = leq;
+
+ return dict;
+}
+
+/* really __gl_dictListDeleteDict */
+void dictDeleteDict( Dict *dict )
+{
+ DictNode *node;
+
+ for( node = dict->head.next; node != &dict->head; node = node->next ) {
+ memFree( node );
+ }
+ memFree( dict );
+}
+
+/* really __gl_dictListInsertBefore */
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key )
+{
+ DictNode *newNode;
+
+ do {
+ node = node->prev;
+ } while( node->key != NULL && ! (*dict->leq)(dict->frame, node->key, key));
+
+ newNode = (DictNode *) memAlloc( sizeof( DictNode ));
+ if (newNode == NULL) return NULL;
+
+ newNode->key = key;
+ newNode->next = node->next;
+ node->next->prev = newNode;
+ newNode->prev = node;
+ node->next = newNode;
+
+ return newNode;
+}
+
+/* really __gl_dictListDelete */
+void dictDelete( Dict *dict, DictNode *node ) /*ARGSUSED*/
+{
+ node->next->prev = node->prev;
+ node->prev->next = node->next;
+ memFree( node );
+}
+
+/* really __gl_dictListSearch */
+DictNode *dictSearch( Dict *dict, DictKey key )
+{
+ DictNode *node = &dict->head;
+
+ do {
+ node = node->next;
+ } while( node->key != NULL && ! (*dict->leq)(dict->frame, key, node->key));
+
+ return node;
+}
diff --git a/Source/ThirdParty/glu/libtess/dict.h b/Source/ThirdParty/glu/libtess/dict.h
new file mode 100644
index 000000000..7851bac31
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/dict.h
@@ -0,0 +1,107 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/dict.h#5 $
+*/
+
+#ifndef __dict_list_h_
+#define __dict_list_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define DictKey DictListKey
+#define Dict DictList
+#define DictNode DictListNode
+
+#define dictNewDict(frame,leq) __gl_dictListNewDict(frame,leq)
+#define dictDeleteDict(dict) __gl_dictListDeleteDict(dict)
+
+#define dictSearch(dict,key) __gl_dictListSearch(dict,key)
+#define dictInsert(dict,key) __gl_dictListInsert(dict,key)
+#define dictInsertBefore(dict,node,key) __gl_dictListInsertBefore(dict,node,key)
+#define dictDelete(dict,node) __gl_dictListDelete(dict,node)
+
+#define dictKey(n) __gl_dictListKey(n)
+#define dictSucc(n) __gl_dictListSucc(n)
+#define dictPred(n) __gl_dictListPred(n)
+#define dictMin(d) __gl_dictListMin(d)
+#define dictMax(d) __gl_dictListMax(d)
+
+
+
+typedef void *DictKey;
+typedef struct Dict Dict;
+typedef struct DictNode DictNode;
+
+Dict *dictNewDict(
+ void *frame,
+ int (*leq)(void *frame, DictKey key1, DictKey key2) );
+
+void dictDeleteDict( Dict *dict );
+
+/* Search returns the node with the smallest key greater than or equal
+ * to the given key. If there is no such key, returns a node whose
+ * key is NULL. Similarly, Succ(Max(d)) has a NULL key, etc.
+ */
+DictNode *dictSearch( Dict *dict, DictKey key );
+DictNode *dictInsertBefore( Dict *dict, DictNode *node, DictKey key );
+void dictDelete( Dict *dict, DictNode *node );
+
+#define __gl_dictListKey(n) ((n)->key)
+#define __gl_dictListSucc(n) ((n)->next)
+#define __gl_dictListPred(n) ((n)->prev)
+#define __gl_dictListMin(d) ((d)->head.next)
+#define __gl_dictListMax(d) ((d)->head.prev)
+#define __gl_dictListInsert(d,k) (dictInsertBefore((d),&(d)->head,(k)))
+
+
+/*** Private data structures ***/
+
+struct DictNode {
+ DictKey key;
+ DictNode *next;
+ DictNode *prev;
+};
+
+struct Dict {
+ DictNode head;
+ void *frame;
+ int (*leq)(void *frame, DictKey key1, DictKey key2);
+};
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/geom.c b/Source/ThirdParty/glu/libtess/geom.c
new file mode 100644
index 000000000..461d8b4a2
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/geom.c
@@ -0,0 +1,271 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/geom.c#5 $
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include "mesh.h"
+#include "geom.h"
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v )
+{
+ /* Returns TRUE if u is lexicographically <= v. */
+
+ return VertLeq( u, v );
+}
+
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->t = 0 and
+ * let r be the negated result (this evaluates (uw)(v->s)), then
+ * r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
+ */
+ GLdouble gapL, gapR;
+
+ assert( VertLeq( u, v ) && VertLeq( v, w ));
+
+ gapL = v->s - u->s;
+ gapR = w->s - v->s;
+
+ if( gapL + gapR > 0 ) {
+ if( gapL < gapR ) {
+ return (v->t - u->t) + (u->t - w->t) * (gapL / (gapL + gapR));
+ } else {
+ return (v->t - w->t) + (w->t - u->t) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+}
+
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Returns a number whose sign matches EdgeEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ GLdouble gapL, gapR;
+
+ assert( VertLeq( u, v ) && VertLeq( v, w ));
+
+ gapL = v->s - u->s;
+ gapR = w->s - v->s;
+
+ if( gapL + gapR > 0 ) {
+ return (v->t - w->t) * gapL + (v->t - u->t) * gapR;
+ }
+ /* vertical line */
+ return 0;
+}
+
+
+/***********************************************************************
+ * Define versions of EdgeSign, EdgeEval with s and t transposed.
+ */
+
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Given three vertices u,v,w such that TransLeq(u,v) && TransLeq(v,w),
+ * evaluates the t-coord of the edge uw at the s-coord of the vertex v.
+ * Returns v->s - (uw)(v->t), ie. the signed distance from uw to v.
+ * If uw is vertical (and thus passes thru v), the result is zero.
+ *
+ * The calculation is extremely accurate and stable, even when v
+ * is very close to u or w. In particular if we set v->s = 0 and
+ * let r be the negated result (this evaluates (uw)(v->t)), then
+ * r is guaranteed to satisfy MIN(u->s,w->s) <= r <= MAX(u->s,w->s).
+ */
+ GLdouble gapL, gapR;
+
+ assert( TransLeq( u, v ) && TransLeq( v, w ));
+
+ gapL = v->t - u->t;
+ gapR = w->t - v->t;
+
+ if( gapL + gapR > 0 ) {
+ if( gapL < gapR ) {
+ return (v->s - u->s) + (u->s - w->s) * (gapL / (gapL + gapR));
+ } else {
+ return (v->s - w->s) + (w->s - u->s) * (gapR / (gapL + gapR));
+ }
+ }
+ /* vertical line */
+ return 0;
+}
+
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* Returns a number whose sign matches TransEval(u,v,w) but which
+ * is cheaper to evaluate. Returns > 0, == 0 , or < 0
+ * as v is above, on, or below the edge uw.
+ */
+ GLdouble gapL, gapR;
+
+ assert( TransLeq( u, v ) && TransLeq( v, w ));
+
+ gapL = v->t - u->t;
+ gapR = w->t - v->t;
+
+ if( gapL + gapR > 0 ) {
+ return (v->s - w->s) * gapL + (v->s - u->s) * gapR;
+ }
+ /* vertical line */
+ return 0;
+}
+
+
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w )
+{
+ /* For almost-degenerate situations, the results are not reliable.
+ * Unless the floating-point arithmetic can be performed without
+ * rounding errors, *any* implementation will give incorrect results
+ * on some degenerate inputs, so the client must have some way to
+ * handle this situation.
+ */
+ return (u->s*(v->t - w->t) + v->s*(w->t - u->t) + w->s*(u->t - v->t)) >= 0;
+}
+
+/* Given parameters a,x,b,y returns the value (b*x+a*y)/(a+b),
+ * or (x+y)/2 if a==b==0. It requires that a,b >= 0, and enforces
+ * this in the rare case that one argument is slightly negative.
+ * The implementation is extremely stable numerically.
+ * In particular it guarantees that the result r satisfies
+ * MIN(x,y) <= r <= MAX(x,y), and the results are very accurate
+ * even when a and b differ greatly in magnitude.
+ */
+#define RealInterpolate(a,x,b,y) \
+ (a = (a < 0) ? 0 : a, b = (b < 0) ? 0 : b, \
+ ((a <= b) ? ((b == 0) ? ((x+y) / 2) \
+ : (x + (y-x) * (a/(a+b)))) \
+ : (y + (x-y) * (b/(a+b)))))
+
+#ifndef FOR_TRITE_TEST_PROGRAM
+#define Interpolate(a,x,b,y) RealInterpolate(a,x,b,y)
+#else
+
+/* Claim: the ONLY property the sweep algorithm relies on is that
+ * MIN(x,y) <= r <= MAX(x,y). This is a nasty way to test that.
+ */
+#include <stdlib.h>
+extern int RandomInterpolate;
+
+GLdouble Interpolate( GLdouble a, GLdouble x, GLdouble b, GLdouble y)
+{
+printf("*********************%d\n",RandomInterpolate);
+ if( RandomInterpolate ) {
+ a = 1.2 * drand48() - 0.1;
+ a = (a < 0) ? 0 : ((a > 1) ? 1 : a);
+ b = 1.0 - a;
+ }
+ return RealInterpolate(a,x,b,y);
+}
+
+#endif
+
+#define Swap(a,b) do { GLUvertex *t = a; a = b; b = t; } while(0)
+
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+ GLUvertex *o2, GLUvertex *d2,
+ GLUvertex *v )
+/* Given edges (o1,d1) and (o2,d2), compute their point of intersection.
+ * The computed point is guaranteed to lie in the intersection of the
+ * bounding rectangles defined by each edge.
+ */
+{
+ GLdouble z1, z2;
+
+ /* This is certainly not the most efficient way to find the intersection
+ * of two line segments, but it is very numerically stable.
+ *
+ * Strategy: find the two middle vertices in the VertLeq ordering,
+ * and interpolate the intersection s-value from these. Then repeat
+ * using the TransLeq ordering to find the intersection t-value.
+ */
+
+ if( ! VertLeq( o1, d1 )) { Swap( o1, d1 ); }
+ if( ! VertLeq( o2, d2 )) { Swap( o2, d2 ); }
+ if( ! VertLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+ if( ! VertLeq( o2, d1 )) {
+ /* Technically, no intersection -- do our best */
+ v->s = (o2->s + d1->s) / 2;
+ } else if( VertLeq( d1, d2 )) {
+ /* Interpolate between o2 and d1 */
+ z1 = EdgeEval( o1, o2, d1 );
+ z2 = EdgeEval( o2, d1, d2 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->s = Interpolate( z1, o2->s, z2, d1->s );
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = EdgeSign( o1, o2, d1 );
+ z2 = -EdgeSign( o1, d2, d1 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->s = Interpolate( z1, o2->s, z2, d2->s );
+ }
+
+ /* Now repeat the process for t */
+
+ if( ! TransLeq( o1, d1 )) { Swap( o1, d1 ); }
+ if( ! TransLeq( o2, d2 )) { Swap( o2, d2 ); }
+ if( ! TransLeq( o1, o2 )) { Swap( o1, o2 ); Swap( d1, d2 ); }
+
+ if( ! TransLeq( o2, d1 )) {
+ /* Technically, no intersection -- do our best */
+ v->t = (o2->t + d1->t) / 2;
+ } else if( TransLeq( d1, d2 )) {
+ /* Interpolate between o2 and d1 */
+ z1 = TransEval( o1, o2, d1 );
+ z2 = TransEval( o2, d1, d2 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->t = Interpolate( z1, o2->t, z2, d1->t );
+ } else {
+ /* Interpolate between o2 and d2 */
+ z1 = TransSign( o1, o2, d1 );
+ z2 = -TransSign( o1, d2, d1 );
+ if( z1+z2 < 0 ) { z1 = -z1; z2 = -z2; }
+ v->t = Interpolate( z1, o2->t, z2, d2->t );
+ }
+}
diff --git a/Source/ThirdParty/glu/libtess/geom.h b/Source/ThirdParty/glu/libtess/geom.h
new file mode 100644
index 000000000..b4d0c6678
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/geom.h
@@ -0,0 +1,90 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/geom.h#5 $
+*/
+
+#ifndef __geom_h_
+#define __geom_h_
+
+#include "mesh.h"
+
+#ifdef NO_BRANCH_CONDITIONS
+/* MIPS architecture has special instructions to evaluate boolean
+ * conditions -- more efficient than branching, IF you can get the
+ * compiler to generate the right instructions (SGI compiler doesn't)
+ */
+#define VertEq(u,v) (((u)->s == (v)->s) & ((u)->t == (v)->t))
+#define VertLeq(u,v) (((u)->s < (v)->s) | \
+ ((u)->s == (v)->s & (u)->t <= (v)->t))
+#else
+#define VertEq(u,v) ((u)->s == (v)->s && (u)->t == (v)->t)
+#define VertLeq(u,v) (((u)->s < (v)->s) || \
+ ((u)->s == (v)->s && (u)->t <= (v)->t))
+#endif
+
+#define EdgeEval(u,v,w) __gl_edgeEval(u,v,w)
+#define EdgeSign(u,v,w) __gl_edgeSign(u,v,w)
+
+/* Versions of VertLeq, EdgeSign, EdgeEval with s and t transposed. */
+
+#define TransLeq(u,v) (((u)->t < (v)->t) || \
+ ((u)->t == (v)->t && (u)->s <= (v)->s))
+#define TransEval(u,v,w) __gl_transEval(u,v,w)
+#define TransSign(u,v,w) __gl_transSign(u,v,w)
+
+
+#define EdgeGoesLeft(e) VertLeq( (e)->Dst, (e)->Org )
+#define EdgeGoesRight(e) VertLeq( (e)->Org, (e)->Dst )
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define VertL1dist(u,v) (ABS(u->s - v->s) + ABS(u->t - v->t))
+
+#define VertCCW(u,v,w) __gl_vertCCW(u,v,w)
+
+int __gl_vertLeq( GLUvertex *u, GLUvertex *v );
+GLdouble __gl_edgeEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_edgeSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_transEval( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+GLdouble __gl_transSign( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+int __gl_vertCCW( GLUvertex *u, GLUvertex *v, GLUvertex *w );
+void __gl_edgeIntersect( GLUvertex *o1, GLUvertex *d1,
+ GLUvertex *o2, GLUvertex *d2,
+ GLUvertex *v );
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/memalloc.c b/Source/ThirdParty/glu/libtess/memalloc.c
new file mode 100644
index 000000000..bd5b4ac79
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/memalloc.c
@@ -0,0 +1,62 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/memalloc.c#5 $
+*/
+
+#include "memalloc.h"
+#include "string.h"
+
+int __gl_memInit( size_t maxFast )
+{
+#ifndef NO_MALLOPT
+/* mallopt( M_MXFAST, maxFast );*/
+#ifdef MEMORY_DEBUG
+ mallopt( M_DEBUG, 1 );
+#endif
+#endif
+ return 1;
+}
+
+#ifdef MEMORY_DEBUG
+void *__gl_memAlloc( size_t n )
+{
+ return memset( malloc( n ), 0xa5, n );
+}
+#endif
+
diff --git a/Source/ThirdParty/glu/libtess/memalloc.h b/Source/ThirdParty/glu/libtess/memalloc.h
new file mode 100644
index 000000000..1e37f7ad5
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/memalloc.h
@@ -0,0 +1,61 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/memalloc.h#5 $
+*/
+
+#ifndef __memalloc_simple_h_
+#define __memalloc_simple_h_
+
+#include <stdlib.h>
+
+#define memRealloc realloc
+#define memFree free
+
+#define memInit __gl_memInit
+/*extern void __gl_memInit( size_t );*/
+extern int __gl_memInit( size_t );
+
+#ifndef MEMORY_DEBUG
+#define memAlloc malloc
+#else
+#define memAlloc __gl_memAlloc
+extern void * __gl_memAlloc( size_t );
+#endif
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/mesh.c b/Source/ThirdParty/glu/libtess/mesh.c
new file mode 100644
index 000000000..7305fab1d
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/mesh.c
@@ -0,0 +1,796 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/mesh.c#6 $
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include "mesh.h"
+#include "memalloc.h"
+
+#define TRUE 1
+#define FALSE 0
+
+static GLUvertex *allocVertex()
+{
+ return (GLUvertex *)memAlloc( sizeof( GLUvertex ));
+}
+
+static GLUface *allocFace()
+{
+ return (GLUface *)memAlloc( sizeof( GLUface ));
+}
+
+/************************ Utility Routines ************************/
+
+/* Allocate and free half-edges in pairs for efficiency.
+ * The *only* place that should use this fact is allocation/free.
+ */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+/* MakeEdge creates a new pair of half-edges which form their own loop.
+ * No vertex or face structures are allocated, but these must be assigned
+ * before the current edge operation is completed.
+ */
+static GLUhalfEdge *MakeEdge( GLUhalfEdge *eNext )
+{
+ GLUhalfEdge *e;
+ GLUhalfEdge *eSym;
+ GLUhalfEdge *ePrev;
+ EdgePair *pair = (EdgePair *)memAlloc( sizeof( EdgePair ));
+ if (pair == NULL) return NULL;
+
+ e = &pair->e;
+ eSym = &pair->eSym;
+
+ /* Make sure eNext points to the first edge of the edge pair */
+ if( eNext->Sym < eNext ) { eNext = eNext->Sym; }
+
+ /* Insert in circular doubly-linked list before eNext.
+ * Note that the prev pointer is stored in Sym->next.
+ */
+ ePrev = eNext->Sym->next;
+ eSym->next = ePrev;
+ ePrev->Sym->next = e;
+ e->next = eNext;
+ eNext->Sym->next = eSym;
+
+ e->Sym = eSym;
+ e->Onext = e;
+ e->Lnext = eSym;
+ e->Org = NULL;
+ e->Lface = NULL;
+ e->winding = 0;
+ e->activeRegion = NULL;
+
+ eSym->Sym = e;
+ eSym->Onext = eSym;
+ eSym->Lnext = e;
+ eSym->Org = NULL;
+ eSym->Lface = NULL;
+ eSym->winding = 0;
+ eSym->activeRegion = NULL;
+
+ return e;
+}
+
+/* Splice( a, b ) is best described by the Guibas/Stolfi paper or the
+ * CS348a notes (see mesh.h). Basically it modifies the mesh so that
+ * a->Onext and b->Onext are exchanged. This can have various effects
+ * depending on whether a and b belong to different face or vertex rings.
+ * For more explanation see __gl_meshSplice() below.
+ */
+static void Splice( GLUhalfEdge *a, GLUhalfEdge *b )
+{
+ GLUhalfEdge *aOnext = a->Onext;
+ GLUhalfEdge *bOnext = b->Onext;
+
+ aOnext->Sym->Lnext = b;
+ bOnext->Sym->Lnext = a;
+ a->Onext = bOnext;
+ b->Onext = aOnext;
+}
+
+/* MakeVertex( newVertex, eOrig, vNext ) attaches a new vertex and makes it the
+ * origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
+ * a place to insert the new vertex in the global vertex list. We insert
+ * the new vertex *before* vNext so that algorithms which walk the vertex
+ * list will not see the newly created vertices.
+ */
+static void MakeVertex( GLUvertex *newVertex,
+ GLUhalfEdge *eOrig, GLUvertex *vNext )
+{
+ GLUhalfEdge *e;
+ GLUvertex *vPrev;
+ GLUvertex *vNew = newVertex;
+
+ assert(vNew != NULL);
+
+ /* insert in circular doubly-linked list before vNext */
+ vPrev = vNext->prev;
+ vNew->prev = vPrev;
+ vPrev->next = vNew;
+ vNew->next = vNext;
+ vNext->prev = vNew;
+
+ vNew->anEdge = eOrig;
+ vNew->data = NULL;
+ /* leave coords, s, t undefined */
+
+ /* fix other edges on this vertex loop */
+ e = eOrig;
+ do {
+ e->Org = vNew;
+ e = e->Onext;
+ } while( e != eOrig );
+}
+
+/* MakeFace( newFace, eOrig, fNext ) attaches a new face and makes it the left
+ * face of all edges in the face loop to which eOrig belongs. "fNext" gives
+ * a place to insert the new face in the global face list. We insert
+ * the new face *before* fNext so that algorithms which walk the face
+ * list will not see the newly created faces.
+ */
+static void MakeFace( GLUface *newFace, GLUhalfEdge *eOrig, GLUface *fNext )
+{
+ GLUhalfEdge *e;
+ GLUface *fPrev;
+ GLUface *fNew = newFace;
+
+ assert(fNew != NULL);
+
+ /* insert in circular doubly-linked list before fNext */
+ fPrev = fNext->prev;
+ fNew->prev = fPrev;
+ fPrev->next = fNew;
+ fNew->next = fNext;
+ fNext->prev = fNew;
+
+ fNew->anEdge = eOrig;
+ fNew->data = NULL;
+ fNew->trail = NULL;
+ fNew->marked = FALSE;
+
+ /* The new face is marked "inside" if the old one was. This is a
+ * convenience for the common case where a face has been split in two.
+ */
+ fNew->inside = fNext->inside;
+
+ /* fix other edges on this face loop */
+ e = eOrig;
+ do {
+ e->Lface = fNew;
+ e = e->Lnext;
+ } while( e != eOrig );
+}
+
+/* KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
+ * and removes from the global edge list.
+ */
+static void KillEdge( GLUhalfEdge *eDel )
+{
+ GLUhalfEdge *ePrev, *eNext;
+
+ /* Half-edges are allocated in pairs, see EdgePair above */
+ if( eDel->Sym < eDel ) { eDel = eDel->Sym; }
+
+ /* delete from circular doubly-linked list */
+ eNext = eDel->next;
+ ePrev = eDel->Sym->next;
+ eNext->Sym->next = ePrev;
+ ePrev->Sym->next = eNext;
+
+ memFree( eDel );
+}
+
+
+/* KillVertex( vDel ) destroys a vertex and removes it from the global
+ * vertex list. It updates the vertex loop to point to a given new vertex.
+ */
+static void KillVertex( GLUvertex *vDel, GLUvertex *newOrg )
+{
+ GLUhalfEdge *e, *eStart = vDel->anEdge;
+ GLUvertex *vPrev, *vNext;
+
+ /* change the origin of all affected edges */
+ e = eStart;
+ do {
+ e->Org = newOrg;
+ e = e->Onext;
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ vPrev = vDel->prev;
+ vNext = vDel->next;
+ vNext->prev = vPrev;
+ vPrev->next = vNext;
+
+ memFree( vDel );
+}
+
+/* KillFace( fDel ) destroys a face and removes it from the global face
+ * list. It updates the face loop to point to a given new face.
+ */
+static void KillFace( GLUface *fDel, GLUface *newLface )
+{
+ GLUhalfEdge *e, *eStart = fDel->anEdge;
+ GLUface *fPrev, *fNext;
+
+ /* change the left face of all affected edges */
+ e = eStart;
+ do {
+ e->Lface = newLface;
+ e = e->Lnext;
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ fPrev = fDel->prev;
+ fNext = fDel->next;
+ fNext->prev = fPrev;
+ fPrev->next = fNext;
+
+ memFree( fDel );
+}
+
+
+/****************** Basic Edge Operations **********************/
+
+/* __gl_meshMakeEdge creates one edge, two vertices, and a loop (face).
+ * The loop consists of the two new half-edges.
+ */
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh )
+{
+ GLUvertex *newVertex1= allocVertex();
+ GLUvertex *newVertex2= allocVertex();
+ GLUface *newFace= allocFace();
+ GLUhalfEdge *e;
+
+ /* if any one is null then all get freed */
+ if (newVertex1 == NULL || newVertex2 == NULL || newFace == NULL) {
+ if (newVertex1 != NULL) memFree(newVertex1);
+ if (newVertex2 != NULL) memFree(newVertex2);
+ if (newFace != NULL) memFree(newFace);
+ return NULL;
+ }
+
+ e = MakeEdge( &mesh->eHead );
+ if (e == NULL) return NULL;
+
+ MakeVertex( newVertex1, e, &mesh->vHead );
+ MakeVertex( newVertex2, e->Sym, &mesh->vHead );
+ MakeFace( newFace, e, &mesh->fHead );
+ return e;
+}
+
+
+/* __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * Some special cases:
+ * If eDst == eOrg, the operation has no effect.
+ * If eDst == eOrg->Lnext, the new face will have a single edge.
+ * If eDst == eOrg->Lprev, the old face will have a single edge.
+ * If eDst == eOrg->Onext, the new vertex will have a single edge.
+ * If eDst == eOrg->Oprev, the old vertex will have a single edge.
+ */
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+ int joiningLoops = FALSE;
+ int joiningVertices = FALSE;
+
+ if( eOrg == eDst ) return 1;
+
+ if( eDst->Org != eOrg->Org ) {
+ /* We are merging two disjoint vertices -- destroy eDst->Org */
+ joiningVertices = TRUE;
+ KillVertex( eDst->Org, eOrg->Org );
+ }
+ if( eDst->Lface != eOrg->Lface ) {
+ /* We are connecting two disjoint loops -- destroy eDst->Lface */
+ joiningLoops = TRUE;
+ KillFace( eDst->Lface, eOrg->Lface );
+ }
+
+ /* Change the edge structure */
+ Splice( eDst, eOrg );
+
+ if( ! joiningVertices ) {
+ GLUvertex *newVertex= allocVertex();
+ if (newVertex == NULL) return 0;
+
+ /* We split one vertex into two -- the new vertex is eDst->Org.
+ * Make sure the old vertex points to a valid half-edge.
+ */
+ MakeVertex( newVertex, eDst, eOrg->Org );
+ eOrg->Org->anEdge = eOrg;
+ }
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return 0;
+
+ /* We split one loop into two -- the new loop is eDst->Lface.
+ * Make sure the old face points to a valid half-edge.
+ */
+ MakeFace( newFace, eDst, eOrg->Lface );
+ eOrg->Lface->anEdge = eOrg;
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * This function could be implemented as two calls to __gl_meshSplice
+ * plus a few calls to memFree, but this would allocate and delete
+ * unnecessary vertices and faces.
+ */
+int __gl_meshDelete( GLUhalfEdge *eDel )
+{
+ GLUhalfEdge *eDelSym = eDel->Sym;
+ int joiningLoops = FALSE;
+
+ /* First step: disconnect the origin vertex eDel->Org. We make all
+ * changes to get a consistent mesh in this "intermediate" state.
+ */
+ if( eDel->Lface != eDel->Rface ) {
+ /* We are joining two loops into one -- remove the left face */
+ joiningLoops = TRUE;
+ KillFace( eDel->Lface, eDel->Rface );
+ }
+
+ if( eDel->Onext == eDel ) {
+ KillVertex( eDel->Org, NULL );
+ } else {
+ /* Make sure that eDel->Org and eDel->Rface point to valid half-edges */
+ eDel->Rface->anEdge = eDel->Oprev;
+ eDel->Org->anEdge = eDel->Onext;
+
+ Splice( eDel, eDel->Oprev );
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return 0;
+
+ /* We are splitting one loop into two -- create a new loop for eDel. */
+ MakeFace( newFace, eDel, eDel->Lface );
+ }
+ }
+
+ /* Claim: the mesh is now in a consistent state, except that eDel->Org
+ * may have been deleted. Now we disconnect eDel->Dst.
+ */
+ if( eDelSym->Onext == eDelSym ) {
+ KillVertex( eDelSym->Org, NULL );
+ KillFace( eDelSym->Lface, NULL );
+ } else {
+ /* Make sure that eDel->Dst and eDel->Lface point to valid half-edges */
+ eDel->Lface->anEdge = eDelSym->Oprev;
+ eDelSym->Org->anEdge = eDelSym->Onext;
+ Splice( eDelSym, eDelSym->Oprev );
+ }
+
+ /* Any isolated vertices or faces have already been freed. */
+ KillEdge( eDel );
+
+ return 1;
+}
+
+
+/******************** Other Edge Operations **********************/
+
+/* All these routines can be implemented with the basic edge
+ * operations above. They are provided for convenience and efficiency.
+ */
+
+
+/* __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg )
+{
+ GLUhalfEdge *eNewSym;
+ GLUhalfEdge *eNew = MakeEdge( eOrg );
+ if (eNew == NULL) return NULL;
+
+ eNewSym = eNew->Sym;
+
+ /* Connect the new edge appropriately */
+ Splice( eNew, eOrg->Lnext );
+
+ /* Set the vertex and face information */
+ eNew->Org = eOrg->Dst;
+ {
+ GLUvertex *newVertex= allocVertex();
+ if (newVertex == NULL) return NULL;
+
+ MakeVertex( newVertex, eNewSym, eNew->Org );
+ }
+ eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+ return eNew;
+}
+
+
+/* __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ */
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg )
+{
+ GLUhalfEdge *eNew;
+ GLUhalfEdge *tempHalfEdge= __gl_meshAddEdgeVertex( eOrg );
+ if (tempHalfEdge == NULL) return NULL;
+
+ eNew = tempHalfEdge->Sym;
+
+ /* Disconnect eOrg from eOrg->Dst and connect it to eNew->Org */
+ Splice( eOrg->Sym, eOrg->Sym->Oprev );
+ Splice( eOrg->Sym, eNew );
+
+ /* Set the vertex and face information */
+ eOrg->Dst = eNew->Org;
+ eNew->Dst->anEdge = eNew->Sym; /* may have pointed to eOrg->Sym */
+ eNew->Rface = eOrg->Rface;
+ eNew->winding = eOrg->winding; /* copy old winding information */
+ eNew->Sym->winding = eOrg->Sym->winding;
+
+ return eNew;
+}
+
+
+/* __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * If (eOrg == eDst), the new face will have only two edges.
+ * If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
+ * If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
+ */
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst )
+{
+ GLUhalfEdge *eNewSym;
+ int joiningLoops = FALSE;
+ GLUhalfEdge *eNew = MakeEdge( eOrg );
+ if (eNew == NULL) return NULL;
+
+ eNewSym = eNew->Sym;
+
+ if( eDst->Lface != eOrg->Lface ) {
+ /* We are connecting two disjoint loops -- destroy eDst->Lface */
+ joiningLoops = TRUE;
+ KillFace( eDst->Lface, eOrg->Lface );
+ }
+
+ /* Connect the new edge appropriately */
+ Splice( eNew, eOrg->Lnext );
+ Splice( eNewSym, eDst );
+
+ /* Set the vertex and face information */
+ eNew->Org = eOrg->Dst;
+ eNewSym->Org = eDst->Org;
+ eNew->Lface = eNewSym->Lface = eOrg->Lface;
+
+ /* Make sure the old face points to a valid half-edge */
+ eOrg->Lface->anEdge = eNewSym;
+
+ if( ! joiningLoops ) {
+ GLUface *newFace= allocFace();
+ if (newFace == NULL) return NULL;
+
+ /* We split one loop into two -- the new loop is eNew->Lface */
+ MakeFace( newFace, eNew, eOrg->Lface );
+ }
+ return eNew;
+}
+
+
+/******************** Other Operations **********************/
+
+/* __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a NULL pointer as their
+ * left face. Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ */
+void __gl_meshZapFace( GLUface *fZap )
+{
+ GLUhalfEdge *eStart = fZap->anEdge;
+ GLUhalfEdge *e, *eNext, *eSym;
+ GLUface *fPrev, *fNext;
+
+ /* walk around face, deleting edges whose right face is also NULL */
+ eNext = eStart->Lnext;
+ do {
+ e = eNext;
+ eNext = e->Lnext;
+
+ e->Lface = NULL;
+ if( e->Rface == NULL ) {
+ /* delete the edge -- see __gl_MeshDelete above */
+
+ if( e->Onext == e ) {
+ KillVertex( e->Org, NULL );
+ } else {
+ /* Make sure that e->Org points to a valid half-edge */
+ e->Org->anEdge = e->Onext;
+ Splice( e, e->Oprev );
+ }
+ eSym = e->Sym;
+ if( eSym->Onext == eSym ) {
+ KillVertex( eSym->Org, NULL );
+ } else {
+ /* Make sure that eSym->Org points to a valid half-edge */
+ eSym->Org->anEdge = eSym->Onext;
+ Splice( eSym, eSym->Oprev );
+ }
+ KillEdge( e );
+ }
+ } while( e != eStart );
+
+ /* delete from circular doubly-linked list */
+ fPrev = fZap->prev;
+ fNext = fZap->next;
+ fNext->prev = fPrev;
+ fPrev->next = fNext;
+
+ memFree( fZap );
+}
+
+
+/* __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ */
+GLUmesh *__gl_meshNewMesh( void )
+{
+ GLUvertex *v;
+ GLUface *f;
+ GLUhalfEdge *e;
+ GLUhalfEdge *eSym;
+ GLUmesh *mesh = (GLUmesh *)memAlloc( sizeof( GLUmesh ));
+ if (mesh == NULL) {
+ return NULL;
+ }
+
+ v = &mesh->vHead;
+ f = &mesh->fHead;
+ e = &mesh->eHead;
+ eSym = &mesh->eHeadSym;
+
+ v->next = v->prev = v;
+ v->anEdge = NULL;
+ v->data = NULL;
+
+ f->next = f->prev = f;
+ f->anEdge = NULL;
+ f->data = NULL;
+ f->trail = NULL;
+ f->marked = FALSE;
+ f->inside = FALSE;
+
+ e->next = e;
+ e->Sym = eSym;
+ e->Onext = NULL;
+ e->Lnext = NULL;
+ e->Org = NULL;
+ e->Lface = NULL;
+ e->winding = 0;
+ e->activeRegion = NULL;
+
+ eSym->next = eSym;
+ eSym->Sym = e;
+ eSym->Onext = NULL;
+ eSym->Lnext = NULL;
+ eSym->Org = NULL;
+ eSym->Lface = NULL;
+ eSym->winding = 0;
+ eSym->activeRegion = NULL;
+
+ return mesh;
+}
+
+
+/* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ */
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 )
+{
+ GLUface *f1 = &mesh1->fHead;
+ GLUvertex *v1 = &mesh1->vHead;
+ GLUhalfEdge *e1 = &mesh1->eHead;
+ GLUface *f2 = &mesh2->fHead;
+ GLUvertex *v2 = &mesh2->vHead;
+ GLUhalfEdge *e2 = &mesh2->eHead;
+
+ /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
+ if( f2->next != f2 ) {
+ f1->prev->next = f2->next;
+ f2->next->prev = f1->prev;
+ f2->prev->next = f1;
+ f1->prev = f2->prev;
+ }
+
+ if( v2->next != v2 ) {
+ v1->prev->next = v2->next;
+ v2->next->prev = v1->prev;
+ v2->prev->next = v1;
+ v1->prev = v2->prev;
+ }
+
+ if( e2->next != e2 ) {
+ e1->Sym->next->Sym->next = e2->next;
+ e2->next->Sym->next = e1->Sym->next;
+ e2->Sym->next->Sym->next = e1;
+ e1->Sym->next = e2->Sym->next;
+ }
+
+ memFree( mesh2 );
+ return mesh1;
+}
+
+
+#ifdef DELETE_BY_ZAPPING
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+ GLUface *fHead = &mesh->fHead;
+
+ while( fHead->next != fHead ) {
+ __gl_meshZapFace( fHead->next );
+ }
+ assert( mesh->vHead.next == &mesh->vHead );
+
+ memFree( mesh );
+}
+
+#else
+
+/* __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ */
+void __gl_meshDeleteMesh( GLUmesh *mesh )
+{
+ GLUface *f, *fNext;
+ GLUvertex *v, *vNext;
+ GLUhalfEdge *e, *eNext;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+ fNext = f->next;
+ memFree( f );
+ }
+
+ for( v = mesh->vHead.next; v != &mesh->vHead; v = vNext ) {
+ vNext = v->next;
+ memFree( v );
+ }
+
+ for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+ /* One call frees both e and e->Sym (see EdgePair above) */
+ eNext = e->next;
+ memFree( e );
+ }
+
+ memFree( mesh );
+}
+
+#endif
+
+#ifndef NDEBUG
+
+/* __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+void __gl_meshCheckMesh( GLUmesh *mesh )
+{
+ GLUface *fHead = &mesh->fHead;
+ GLUvertex *vHead = &mesh->vHead;
+ GLUhalfEdge *eHead = &mesh->eHead;
+ GLUface *f, *fPrev;
+ GLUvertex *v, *vPrev;
+ GLUhalfEdge *e, *ePrev;
+
+ fPrev = fHead;
+ for( fPrev = fHead ; (f = fPrev->next) != fHead; fPrev = f) {
+ assert( f->prev == fPrev );
+ e = f->anEdge;
+ do {
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ assert( e->Lface == f );
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ assert( f->prev == fPrev && f->anEdge == NULL && f->data == NULL );
+
+ vPrev = vHead;
+ for( vPrev = vHead ; (v = vPrev->next) != vHead; vPrev = v) {
+ assert( v->prev == vPrev );
+ e = v->anEdge;
+ do {
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ assert( e->Org == v );
+ e = e->Onext;
+ } while( e != v->anEdge );
+ }
+ assert( v->prev == vPrev && v->anEdge == NULL && v->data == NULL );
+
+ ePrev = eHead;
+ for( ePrev = eHead ; (e = ePrev->next) != eHead; ePrev = e) {
+ assert( e->Sym->next == ePrev->Sym );
+ assert( e->Sym != e );
+ assert( e->Sym->Sym == e );
+ assert( e->Org != NULL );
+ assert( e->Dst != NULL );
+ assert( e->Lnext->Onext->Sym == e );
+ assert( e->Onext->Sym->Lnext == e );
+ }
+ assert( e->Sym->next == ePrev->Sym
+ && e->Sym == &mesh->eHeadSym
+ && e->Sym->Sym == e
+ && e->Org == NULL && e->Dst == NULL
+ && e->Lface == NULL && e->Rface == NULL );
+}
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/mesh.h b/Source/ThirdParty/glu/libtess/mesh.h
new file mode 100644
index 000000000..a92de0e96
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/mesh.h
@@ -0,0 +1,273 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/mesh.h#5 $
+*/
+
+#ifndef __mesh_h_
+#define __mesh_h_
+
+#include <internal_glu.h>
+
+typedef struct GLUmesh GLUmesh;
+
+typedef struct GLUvertex GLUvertex;
+typedef struct GLUface GLUface;
+typedef struct GLUhalfEdge GLUhalfEdge;
+
+typedef struct ActiveRegion ActiveRegion; /* Internal data */
+
+/* The mesh structure is similar in spirit, notation, and operations
+ * to the "quad-edge" structure (see L. Guibas and J. Stolfi, Primitives
+ * for the manipulation of general subdivisions and the computation of
+ * Voronoi diagrams, ACM Transactions on Graphics, 4(2):74-123, April 1985).
+ * For a simplified description, see the course notes for CS348a,
+ * "Mathematical Foundations of Computer Graphics", available at the
+ * Stanford bookstore (and taught during the fall quarter).
+ * The implementation also borrows a tiny subset of the graph-based approach
+ * use in Mantyla's Geometric Work Bench (see M. Mantyla, An Introduction
+ * to Sold Modeling, Computer Science Press, Rockville, Maryland, 1988).
+ *
+ * The fundamental data structure is the "half-edge". Two half-edges
+ * go together to make an edge, but they point in opposite directions.
+ * Each half-edge has a pointer to its mate (the "symmetric" half-edge Sym),
+ * its origin vertex (Org), the face on its left side (Lface), and the
+ * adjacent half-edges in the CCW direction around the origin vertex
+ * (Onext) and around the left face (Lnext). There is also a "next"
+ * pointer for the global edge list (see below).
+ *
+ * The notation used for mesh navigation:
+ * Sym = the mate of a half-edge (same edge, but opposite direction)
+ * Onext = edge CCW around origin vertex (keep same origin)
+ * Dnext = edge CCW around destination vertex (keep same dest)
+ * Lnext = edge CCW around left face (dest becomes new origin)
+ * Rnext = edge CCW around right face (origin becomes new dest)
+ *
+ * "prev" means to substitute CW for CCW in the definitions above.
+ *
+ * The mesh keeps global lists of all vertices, faces, and edges,
+ * stored as doubly-linked circular lists with a dummy header node.
+ * The mesh stores pointers to these dummy headers (vHead, fHead, eHead).
+ *
+ * The circular edge list is special; since half-edges always occur
+ * in pairs (e and e->Sym), each half-edge stores a pointer in only
+ * one direction. Starting at eHead and following the e->next pointers
+ * will visit each *edge* once (ie. e or e->Sym, but not both).
+ * e->Sym stores a pointer in the opposite direction, thus it is
+ * always true that e->Sym->next->Sym->next == e.
+ *
+ * Each vertex has a pointer to next and previous vertices in the
+ * circular list, and a pointer to a half-edge with this vertex as
+ * the origin (NULL if this is the dummy header). There is also a
+ * field "data" for client data.
+ *
+ * Each face has a pointer to the next and previous faces in the
+ * circular list, and a pointer to a half-edge with this face as
+ * the left face (NULL if this is the dummy header). There is also
+ * a field "data" for client data.
+ *
+ * Note that what we call a "face" is really a loop; faces may consist
+ * of more than one loop (ie. not simply connected), but there is no
+ * record of this in the data structure. The mesh may consist of
+ * several disconnected regions, so it may not be possible to visit
+ * the entire mesh by starting at a half-edge and traversing the edge
+ * structure.
+ *
+ * The mesh does NOT support isolated vertices; a vertex is deleted along
+ * with its last edge. Similarly when two faces are merged, one of the
+ * faces is deleted (see __gl_meshDelete below). For mesh operations,
+ * all face (loop) and vertex pointers must not be NULL. However, once
+ * mesh manipulation is finished, __gl_MeshZapFace can be used to delete
+ * faces of the mesh, one at a time. All external faces can be "zapped"
+ * before the mesh is returned to the client; then a NULL face indicates
+ * a region which is not part of the output polygon.
+ */
+
+struct GLUvertex {
+ GLUvertex *next; /* next vertex (never NULL) */
+ GLUvertex *prev; /* previous vertex (never NULL) */
+ GLUhalfEdge *anEdge; /* a half-edge with this origin */
+ void *data; /* client's data */
+
+ /* Internal data (keep hidden) */
+ GLdouble coords[3]; /* vertex location in 3D */
+ GLdouble s, t; /* projection onto the sweep plane */
+ long pqHandle; /* to allow deletion from priority queue */
+};
+
+struct GLUface {
+ GLUface *next; /* next face (never NULL) */
+ GLUface *prev; /* previous face (never NULL) */
+ GLUhalfEdge *anEdge; /* a half edge with this left face */
+ void *data; /* room for client's data */
+
+ /* Internal data (keep hidden) */
+ GLUface *trail; /* "stack" for conversion to strips */
+ GLboolean marked; /* flag for conversion to strips */
+ GLboolean inside; /* this face is in the polygon interior */
+};
+
+struct GLUhalfEdge {
+ GLUhalfEdge *next; /* doubly-linked list (prev==Sym->next) */
+ GLUhalfEdge *Sym; /* same edge, opposite direction */
+ GLUhalfEdge *Onext; /* next edge CCW around origin */
+ GLUhalfEdge *Lnext; /* next edge CCW around left face */
+ GLUvertex *Org; /* origin vertex (Overtex too long) */
+ GLUface *Lface; /* left face */
+
+ /* Internal data (keep hidden) */
+ ActiveRegion *activeRegion; /* a region with this upper edge (sweep.c) */
+ int winding; /* change in winding number when crossing
+ from the right face to the left face */
+};
+
+#define Rface Sym->Lface
+#define Dst Sym->Org
+
+#define Oprev Sym->Lnext
+#define Lprev Onext->Sym
+#define Dprev Lnext->Sym
+#define Rprev Sym->Onext
+#define Dnext Rprev->Sym /* 3 pointers */
+#define Rnext Oprev->Sym /* 3 pointers */
+
+
+struct GLUmesh {
+ GLUvertex vHead; /* dummy header for vertex list */
+ GLUface fHead; /* dummy header for face list */
+ GLUhalfEdge eHead; /* dummy header for edge list */
+ GLUhalfEdge eHeadSym; /* and its symmetric counterpart */
+};
+
+/* The mesh operations below have three motivations: completeness,
+ * convenience, and efficiency. The basic mesh operations are MakeEdge,
+ * Splice, and Delete. All the other edge operations can be implemented
+ * in terms of these. The other operations are provided for convenience
+ * and/or efficiency.
+ *
+ * When a face is split or a vertex is added, they are inserted into the
+ * global list *before* the existing vertex or face (ie. e->Org or e->Lface).
+ * This makes it easier to process all vertices or faces in the global lists
+ * without worrying about processing the same data twice. As a convenience,
+ * when a face is split, the "inside" flag is copied from the old face.
+ * Other internal data (v->data, v->activeRegion, f->data, f->marked,
+ * f->trail, e->winding) is set to zero.
+ *
+ * ********************** Basic Edge Operations **************************
+ *
+ * __gl_meshMakeEdge( mesh ) creates one edge, two vertices, and a loop.
+ * The loop (face) consists of the two new half-edges.
+ *
+ * __gl_meshSplice( eOrg, eDst ) is the basic operation for changing the
+ * mesh connectivity and topology. It changes the mesh so that
+ * eOrg->Onext <- OLD( eDst->Onext )
+ * eDst->Onext <- OLD( eOrg->Onext )
+ * where OLD(...) means the value before the meshSplice operation.
+ *
+ * This can have two effects on the vertex structure:
+ * - if eOrg->Org != eDst->Org, the two vertices are merged together
+ * - if eOrg->Org == eDst->Org, the origin is split into two vertices
+ * In both cases, eDst->Org is changed and eOrg->Org is untouched.
+ *
+ * Similarly (and independently) for the face structure,
+ * - if eOrg->Lface == eDst->Lface, one loop is split into two
+ * - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
+ * In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
+ *
+ * __gl_meshDelete( eDel ) removes the edge eDel. There are several cases:
+ * if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
+ * eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
+ * the newly created loop will contain eDel->Dst. If the deletion of eDel
+ * would create isolated vertices, those are deleted as well.
+ *
+ * ********************** Other Edge Operations **************************
+ *
+ * __gl_meshAddEdgeVertex( eOrg ) creates a new edge eNew such that
+ * eNew == eOrg->Lnext, and eNew->Dst is a newly created vertex.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshSplitEdge( eOrg ) splits eOrg into two edges eOrg and eNew,
+ * such that eNew == eOrg->Lnext. The new vertex is eOrg->Dst == eNew->Org.
+ * eOrg and eNew will have the same left face.
+ *
+ * __gl_meshConnect( eOrg, eDst ) creates a new edge from eOrg->Dst
+ * to eDst->Org, and returns the corresponding half-edge eNew.
+ * If eOrg->Lface == eDst->Lface, this splits one loop into two,
+ * and the newly created loop is eNew->Lface. Otherwise, two disjoint
+ * loops are merged into one, and the loop eDst->Lface is destroyed.
+ *
+ * ************************ Other Operations *****************************
+ *
+ * __gl_meshNewMesh() creates a new mesh with no edges, no vertices,
+ * and no loops (what we usually call a "face").
+ *
+ * __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
+ * both meshes, and returns the new mesh (the old meshes are destroyed).
+ *
+ * __gl_meshDeleteMesh( mesh ) will free all storage for any valid mesh.
+ *
+ * __gl_meshZapFace( fZap ) destroys a face and removes it from the
+ * global face list. All edges of fZap will have a NULL pointer as their
+ * left face. Any edges which also have a NULL pointer as their right face
+ * are deleted entirely (along with any isolated vertices this produces).
+ * An entire mesh can be deleted by zapping its faces, one at a time,
+ * in any order. Zapped faces cannot be used in further mesh operations!
+ *
+ * __gl_meshCheckMesh( mesh ) checks a mesh for self-consistency.
+ */
+
+GLUhalfEdge *__gl_meshMakeEdge( GLUmesh *mesh );
+int __gl_meshSplice( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+int __gl_meshDelete( GLUhalfEdge *eDel );
+
+GLUhalfEdge *__gl_meshAddEdgeVertex( GLUhalfEdge *eOrg );
+GLUhalfEdge *__gl_meshSplitEdge( GLUhalfEdge *eOrg );
+GLUhalfEdge *__gl_meshConnect( GLUhalfEdge *eOrg, GLUhalfEdge *eDst );
+
+GLUmesh *__gl_meshNewMesh( void );
+GLUmesh *__gl_meshUnion( GLUmesh *mesh1, GLUmesh *mesh2 );
+void __gl_meshDeleteMesh( GLUmesh *mesh );
+void __gl_meshZapFace( GLUface *fZap );
+
+#ifdef NDEBUG
+#define __gl_meshCheckMesh( mesh )
+#else
+void __gl_meshCheckMesh( GLUmesh *mesh );
+#endif
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/normal.c b/Source/ThirdParty/glu/libtess/normal.c
new file mode 100644
index 000000000..8fb22f1de
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/normal.c
@@ -0,0 +1,259 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/normal.c#5 $
+*/
+
+#include "gluos.h"
+#include "mesh.h"
+#include "tess.h"
+#include "normal.h"
+#include <math.h>
+#include <assert.h>
+
+#define TRUE 1
+#define FALSE 0
+
+#define Dot(u,v) (u[0]*v[0] + u[1]*v[1] + u[2]*v[2])
+
+#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
+static void Normalize( GLdouble v[3] )
+{
+ GLdouble len = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+
+ assert( len > 0 );
+ len = sqrt( len );
+ v[0] /= len;
+ v[1] /= len;
+ v[2] /= len;
+}
+#endif
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+static int LongAxis( GLdouble v[3] )
+{
+ int i = 0;
+
+ if( ABS(v[1]) > ABS(v[0]) ) { i = 1; }
+ if( ABS(v[2]) > ABS(v[i]) ) { i = 2; }
+ return i;
+}
+
+static void ComputeNormal( GLUtesselator *tess, GLdouble norm[3] )
+{
+ GLUvertex *v, *v1, *v2;
+ GLdouble c, tLen2, maxLen2;
+ GLdouble maxVal[3], minVal[3], d1[3], d2[3], tNorm[3];
+ GLUvertex *maxVert[3], *minVert[3];
+ GLUvertex *vHead = &tess->mesh->vHead;
+ int i;
+
+ maxVal[0] = maxVal[1] = maxVal[2] = -2 * GLU_TESS_MAX_COORD;
+ minVal[0] = minVal[1] = minVal[2] = 2 * GLU_TESS_MAX_COORD;
+
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ for( i = 0; i < 3; ++i ) {
+ c = v->coords[i];
+ if( c < minVal[i] ) { minVal[i] = c; minVert[i] = v; }
+ if( c > maxVal[i] ) { maxVal[i] = c; maxVert[i] = v; }
+ }
+ }
+
+ /* Find two vertices separated by at least 1/sqrt(3) of the maximum
+ * distance between any two vertices
+ */
+ i = 0;
+ if( maxVal[1] - minVal[1] > maxVal[0] - minVal[0] ) { i = 1; }
+ if( maxVal[2] - minVal[2] > maxVal[i] - minVal[i] ) { i = 2; }
+ if( minVal[i] >= maxVal[i] ) {
+ /* All vertices are the same -- normal doesn't matter */
+ norm[0] = 0; norm[1] = 0; norm[2] = 1;
+ return;
+ }
+
+ /* Look for a third vertex which forms the triangle with maximum area
+ * (Length of normal == twice the triangle area)
+ */
+ maxLen2 = 0;
+ v1 = minVert[i];
+ v2 = maxVert[i];
+ d1[0] = v1->coords[0] - v2->coords[0];
+ d1[1] = v1->coords[1] - v2->coords[1];
+ d1[2] = v1->coords[2] - v2->coords[2];
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ d2[0] = v->coords[0] - v2->coords[0];
+ d2[1] = v->coords[1] - v2->coords[1];
+ d2[2] = v->coords[2] - v2->coords[2];
+ tNorm[0] = d1[1]*d2[2] - d1[2]*d2[1];
+ tNorm[1] = d1[2]*d2[0] - d1[0]*d2[2];
+ tNorm[2] = d1[0]*d2[1] - d1[1]*d2[0];
+ tLen2 = tNorm[0]*tNorm[0] + tNorm[1]*tNorm[1] + tNorm[2]*tNorm[2];
+ if( tLen2 > maxLen2 ) {
+ maxLen2 = tLen2;
+ norm[0] = tNorm[0];
+ norm[1] = tNorm[1];
+ norm[2] = tNorm[2];
+ }
+ }
+
+ if( maxLen2 <= 0 ) {
+ /* All points lie on a single line -- any decent normal will do */
+ norm[0] = norm[1] = norm[2] = 0;
+ norm[LongAxis(d1)] = 1;
+ }
+}
+
+
+static void CheckOrientation( GLUtesselator *tess )
+{
+ GLdouble area;
+ GLUface *f, *fHead = &tess->mesh->fHead;
+ GLUvertex *v, *vHead = &tess->mesh->vHead;
+ GLUhalfEdge *e;
+
+ /* When we compute the normal automatically, we choose the orientation
+ * so that the the sum of the signed areas of all contours is non-negative.
+ */
+ area = 0;
+ for( f = fHead->next; f != fHead; f = f->next ) {
+ e = f->anEdge;
+ if( e->winding <= 0 ) continue;
+ do {
+ area += (e->Org->s - e->Dst->s) * (e->Org->t + e->Dst->t);
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ if( area < 0 ) {
+ /* Reverse the orientation by flipping all the t-coordinates */
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->t = - v->t;
+ }
+ tess->tUnit[0] = - tess->tUnit[0];
+ tess->tUnit[1] = - tess->tUnit[1];
+ tess->tUnit[2] = - tess->tUnit[2];
+ }
+}
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#include <stdlib.h>
+extern int RandomSweep;
+#define S_UNIT_X (RandomSweep ? (2*drand48()-1) : 1.0)
+#define S_UNIT_Y (RandomSweep ? (2*drand48()-1) : 0.0)
+#else
+#if defined(SLANTED_SWEEP)
+/* The "feature merging" is not intended to be complete. There are
+ * special cases where edges are nearly parallel to the sweep line
+ * which are not implemented. The algorithm should still behave
+ * robustly (ie. produce a reasonable tesselation) in the presence
+ * of such edges, however it may miss features which could have been
+ * merged. We could minimize this effect by choosing the sweep line
+ * direction to be something unusual (ie. not parallel to one of the
+ * coordinate axes).
+ */
+#define S_UNIT_X 0.50941539564955385 /* Pre-normalized */
+#define S_UNIT_Y 0.86052074622010633
+#else
+#define S_UNIT_X 1.0
+#define S_UNIT_Y 0.0
+#endif
+#endif
+
+/* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess )
+{
+ GLUvertex *v, *vHead = &tess->mesh->vHead;
+ GLdouble norm[3];
+ GLdouble *sUnit, *tUnit;
+ int i, computedNormal = FALSE;
+
+ norm[0] = tess->normal[0];
+ norm[1] = tess->normal[1];
+ norm[2] = tess->normal[2];
+ if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+ ComputeNormal( tess, norm );
+ computedNormal = TRUE;
+ }
+ sUnit = tess->sUnit;
+ tUnit = tess->tUnit;
+ i = LongAxis( norm );
+
+#if defined(FOR_TRITE_TEST_PROGRAM) || defined(TRUE_PROJECT)
+ /* Choose the initial sUnit vector to be approximately perpendicular
+ * to the normal.
+ */
+ Normalize( norm );
+
+ sUnit[i] = 0;
+ sUnit[(i+1)%3] = S_UNIT_X;
+ sUnit[(i+2)%3] = S_UNIT_Y;
+
+ /* Now make it exactly perpendicular */
+ w = Dot( sUnit, norm );
+ sUnit[0] -= w * norm[0];
+ sUnit[1] -= w * norm[1];
+ sUnit[2] -= w * norm[2];
+ Normalize( sUnit );
+
+ /* Choose tUnit so that (sUnit,tUnit,norm) form a right-handed frame */
+ tUnit[0] = norm[1]*sUnit[2] - norm[2]*sUnit[1];
+ tUnit[1] = norm[2]*sUnit[0] - norm[0]*sUnit[2];
+ tUnit[2] = norm[0]*sUnit[1] - norm[1]*sUnit[0];
+ Normalize( tUnit );
+#else
+ /* Project perpendicular to a coordinate axis -- better numerically */
+ sUnit[i] = 0;
+ sUnit[(i+1)%3] = S_UNIT_X;
+ sUnit[(i+2)%3] = S_UNIT_Y;
+
+ tUnit[i] = 0;
+ tUnit[(i+1)%3] = (norm[i] > 0) ? -S_UNIT_Y : S_UNIT_Y;
+ tUnit[(i+2)%3] = (norm[i] > 0) ? S_UNIT_X : -S_UNIT_X;
+#endif
+
+ /* Project the vertices onto the sweep plane */
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->s = Dot( v->coords, sUnit );
+ v->t = Dot( v->coords, tUnit );
+ }
+ if( computedNormal ) {
+ CheckOrientation( tess );
+ }
+}
diff --git a/Source/ThirdParty/glu/libtess/normal.h b/Source/ThirdParty/glu/libtess/normal.h
new file mode 100644
index 000000000..5a687473b
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/normal.h
@@ -0,0 +1,52 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/normal.h#5 $
+*/
+
+#ifndef __normal_h_
+#define __normal_h_
+
+#include "tess.h"
+
+/* __gl_projectPolygon( tess ) determines the polygon normal
+ * and project vertices onto the plane of the polygon.
+ */
+void __gl_projectPolygon( GLUtesselator *tess );
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/priorityq-heap.c b/Source/ThirdParty/glu/libtess/priorityq-heap.c
new file mode 100644
index 000000000..163bde6a8
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/priorityq-heap.c
@@ -0,0 +1,260 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq-heap.c#5 $
+*/
+
+#include <stddef.h>
+#include <assert.h>
+#include <limits.h>
+#include "priorityq-heap.h"
+#include "memalloc.h"
+
+#define INIT_SIZE 32
+
+#define TRUE 1
+#define FALSE 0
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+#define LEQ(x,y) (*pq->leq)(x,y)
+#else
+/* Violates modularity, but a little faster */
+#include "geom.h"
+#define LEQ(x,y) VertLeq((GLUvertex *)x, (GLUvertex *)y)
+#endif
+
+/* really __gl_pqHeapNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+ PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+ if (pq == NULL) return NULL;
+
+ pq->size = 0;
+ pq->max = INIT_SIZE;
+ pq->nodes = (PQnode *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->nodes[0]) );
+ if (pq->nodes == NULL) {
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->handles = (PQhandleElem *)memAlloc( (INIT_SIZE + 1) * sizeof(pq->handles[0]) );
+ if (pq->handles == NULL) {
+ memFree(pq->nodes);
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->initialized = FALSE;
+ pq->freeList = 0;
+ pq->leq = leq;
+
+ pq->nodes[1].handle = 1; /* so that Minimum() returns NULL */
+ pq->handles[1].key = NULL;
+ return pq;
+}
+
+/* really __gl_pqHeapDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+ memFree( pq->handles );
+ memFree( pq->nodes );
+ memFree( pq );
+}
+
+
+static void FloatDown( PriorityQ *pq, long curr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hCurr, hChild;
+ long child;
+
+ hCurr = n[curr].handle;
+ for( ;; ) {
+ child = curr << 1;
+ if( child < pq->size && LEQ( h[n[child+1].handle].key,
+ h[n[child].handle].key )) {
+ ++child;
+ }
+
+ assert(child <= pq->max);
+
+ hChild = n[child].handle;
+ if( child > pq->size || LEQ( h[hCurr].key, h[hChild].key )) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hChild;
+ h[hChild].node = curr;
+ curr = child;
+ }
+}
+
+
+static void FloatUp( PriorityQ *pq, long curr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hCurr, hParent;
+ long parent;
+
+ hCurr = n[curr].handle;
+ for( ;; ) {
+ parent = curr >> 1;
+ hParent = n[parent].handle;
+ if( parent == 0 || LEQ( h[hParent].key, h[hCurr].key )) {
+ n[curr].handle = hCurr;
+ h[hCurr].node = curr;
+ break;
+ }
+ n[curr].handle = hParent;
+ h[hParent].node = curr;
+ curr = parent;
+ }
+}
+
+/* really __gl_pqHeapInit */
+void pqInit( PriorityQ *pq )
+{
+ long i;
+
+ /* This method of building a heap is O(n), rather than O(n lg n). */
+
+ for( i = pq->size; i >= 1; --i ) {
+ FloatDown( pq, i );
+ }
+ pq->initialized = TRUE;
+}
+
+/* really __gl_pqHeapInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+ long curr;
+ PQhandle free;
+
+ curr = ++ pq->size;
+ if( (curr*2) > pq->max ) {
+ PQnode *saveNodes= pq->nodes;
+ PQhandleElem *saveHandles= pq->handles;
+
+ /* If the heap overflows, double its size. */
+ pq->max <<= 1;
+ pq->nodes = (PQnode *)memRealloc( pq->nodes,
+ (size_t)
+ ((pq->max + 1) * sizeof( pq->nodes[0] )));
+ if (pq->nodes == NULL) {
+ pq->nodes = saveNodes; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ pq->handles = (PQhandleElem *)memRealloc( pq->handles,
+ (size_t)
+ ((pq->max + 1) *
+ sizeof( pq->handles[0] )));
+ if (pq->handles == NULL) {
+ pq->handles = saveHandles; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ }
+
+ if( pq->freeList == 0 ) {
+ free = curr;
+ } else {
+ free = pq->freeList;
+ pq->freeList = pq->handles[free].node;
+ }
+
+ pq->nodes[curr].handle = free;
+ pq->handles[free].node = curr;
+ pq->handles[free].key = keyNew;
+
+ if( pq->initialized ) {
+ FloatUp( pq, curr );
+ }
+ assert(free != LONG_MAX);
+ return free;
+}
+
+/* really __gl_pqHeapExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ PQhandle hMin = n[1].handle;
+ PQkey min = h[hMin].key;
+
+ if( pq->size > 0 ) {
+ n[1].handle = n[pq->size].handle;
+ h[n[1].handle].node = 1;
+
+ h[hMin].key = NULL;
+ h[hMin].node = pq->freeList;
+ pq->freeList = hMin;
+
+ if( -- pq->size > 0 ) {
+ FloatDown( pq, 1 );
+ }
+ }
+ return min;
+}
+
+/* really __gl_pqHeapDelete */
+void pqDelete( PriorityQ *pq, PQhandle hCurr )
+{
+ PQnode *n = pq->nodes;
+ PQhandleElem *h = pq->handles;
+ long curr;
+
+ assert( hCurr >= 1 && hCurr <= pq->max && h[hCurr].key != NULL );
+
+ curr = h[hCurr].node;
+ n[curr].handle = n[pq->size].handle;
+ h[n[curr].handle].node = curr;
+
+ if( curr <= -- pq->size ) {
+ if( curr <= 1 || LEQ( h[n[curr>>1].handle].key, h[n[curr].handle].key )) {
+ FloatDown( pq, curr );
+ } else {
+ FloatUp( pq, curr );
+ }
+ }
+ h[hCurr].key = NULL;
+ h[hCurr].node = pq->freeList;
+ pq->freeList = hCurr;
+}
diff --git a/Source/ThirdParty/glu/libtess/priorityq-heap.h b/Source/ThirdParty/glu/libtess/priorityq-heap.h
new file mode 100644
index 000000000..02e443436
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/priorityq-heap.h
@@ -0,0 +1,114 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq-heap.h#5 $
+*/
+
+#ifndef __priorityq_heap_h_
+#define __priorityq_heap_h_
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQHeapKey
+#define PQhandle PQHeapHandle
+#define PriorityQ PriorityQHeap
+
+#define pqNewPriorityQ(leq) __gl_pqHeapNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqHeapDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqHeapInit(pq)
+#define pqInsert(pq,key) __gl_pqHeapInsert(pq,key)
+#define pqMinimum(pq) __gl_pqHeapMinimum(pq)
+#define pqExtractMin(pq) __gl_pqHeapExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqHeapDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqHeapIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef void *PQkey;
+typedef long PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+typedef struct { PQhandle handle; } PQnode;
+typedef struct { PQkey key; PQhandle node; } PQhandleElem;
+
+struct PriorityQ {
+ PQnode *nodes;
+ PQhandleElem *handles;
+ long size, max;
+ PQhandle freeList;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+void pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+
+#define __gl_pqHeapMinimum(pq) ((pq)->handles[(pq)->nodes[1].handle].key)
+#define __gl_pqHeapIsEmpty(pq) ((pq)->size == 0)
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/priorityq-sort.h b/Source/ThirdParty/glu/libtess/priorityq-sort.h
new file mode 100644
index 000000000..12c2f0d4b
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/priorityq-sort.h
@@ -0,0 +1,124 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq-sort.h#5 $
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQSortKey
+#define PQhandle PQSortHandle
+#define PriorityQ PriorityQSort
+
+#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqSortInit(pq)
+#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq) __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+ PriorityQHeap *heap;
+ PQkey *keys;
+ PQkey **order;
+ PQhandle size, max;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+int pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey pqMinimum( PriorityQ *pq );
+int pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/priorityq.c b/Source/ThirdParty/glu/libtess/priorityq.c
new file mode 100644
index 000000000..4b9e1aeae
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/priorityq.c
@@ -0,0 +1,267 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq.c#5 $
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include <limits.h> /* LONG_MAX */
+#include "memalloc.h"
+
+/* Include all the code for the regular heap-based queue here. */
+
+#include "priorityq-heap.c"
+
+/* Now redefine all the function names to map to their "Sort" versions. */
+
+#include "priorityq-sort.h"
+
+/* really __gl_pqSortNewPriorityQ */
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) )
+{
+ PriorityQ *pq = (PriorityQ *)memAlloc( sizeof( PriorityQ ));
+ if (pq == NULL) return NULL;
+
+ pq->heap = __gl_pqHeapNewPriorityQ( leq );
+ if (pq->heap == NULL) {
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->keys = (PQHeapKey *)memAlloc( INIT_SIZE * sizeof(pq->keys[0]) );
+ if (pq->keys == NULL) {
+ __gl_pqHeapDeletePriorityQ(pq->heap);
+ memFree(pq);
+ return NULL;
+ }
+
+ pq->size = 0;
+ pq->max = INIT_SIZE;
+ pq->initialized = FALSE;
+ pq->leq = leq;
+ return pq;
+}
+
+/* really __gl_pqSortDeletePriorityQ */
+void pqDeletePriorityQ( PriorityQ *pq )
+{
+ assert(pq != NULL);
+ if (pq->heap != NULL) __gl_pqHeapDeletePriorityQ( pq->heap );
+ if (pq->order != NULL) memFree( pq->order );
+ if (pq->keys != NULL) memFree( pq->keys );
+ memFree( pq );
+}
+
+
+#define LT(x,y) (! LEQ(y,x))
+#define GT(x,y) (! LEQ(x,y))
+#define Swap(a,b) do{PQkey *tmp = *a; *a = *b; *b = tmp;}while(0)
+
+/* really __gl_pqSortInit */
+int pqInit( PriorityQ *pq )
+{
+ PQkey **p, **r, **i, **j, *piv;
+ struct { PQkey **p, **r; } Stack[50], *top = Stack;
+ unsigned long seed = 2016473283;
+
+ /* Create an array of indirect pointers to the keys, so that we
+ * the handles we have returned are still valid.
+ */
+/*
+ pq->order = (PQHeapKey **)memAlloc( (size_t)
+ (pq->size * sizeof(pq->order[0])) );
+*/
+ pq->order = (PQHeapKey **)memAlloc( (size_t)
+ ((pq->size+1) * sizeof(pq->order[0])) );
+/* the previous line is a patch to compensate for the fact that IBM */
+/* machines return a null on a malloc of zero bytes (unlike SGI), */
+/* so we have to put in this defense to guard against a memory */
+/* fault four lines down. from fossum@austin.ibm.com. */
+ if (pq->order == NULL) return 0;
+
+ p = pq->order;
+ r = p + pq->size - 1;
+ for( piv = pq->keys, i = p; i <= r; ++piv, ++i ) {
+ *i = piv;
+ }
+
+ /* Sort the indirect pointers in descending order,
+ * using randomized Quicksort
+ */
+ top->p = p; top->r = r; ++top;
+ while( --top >= Stack ) {
+ p = top->p;
+ r = top->r;
+ while( r > p + 10 ) {
+ seed = seed * 1539415821 + 1;
+ i = p + seed % (r - p + 1);
+ piv = *i;
+ *i = *p;
+ *p = piv;
+ i = p - 1;
+ j = r + 1;
+ do {
+ do { ++i; } while( GT( **i, *piv ));
+ do { --j; } while( LT( **j, *piv ));
+ Swap( i, j );
+ } while( i < j );
+ Swap( i, j ); /* Undo last swap */
+ if( i - p < r - j ) {
+ top->p = j+1; top->r = r; ++top;
+ r = i-1;
+ } else {
+ top->p = p; top->r = i-1; ++top;
+ p = j+1;
+ }
+ }
+ /* Insertion sort small lists */
+ for( i = p+1; i <= r; ++i ) {
+ piv = *i;
+ for( j = i; j > p && LT( **(j-1), *piv ); --j ) {
+ *j = *(j-1);
+ }
+ *j = piv;
+ }
+ }
+ pq->max = pq->size;
+ pq->initialized = TRUE;
+ __gl_pqHeapInit( pq->heap ); /* always succeeds */
+
+#ifndef NDEBUG
+ p = pq->order;
+ r = p + pq->size - 1;
+ for( i = p; i < r; ++i ) {
+ assert( LEQ( **(i+1), **i ));
+ }
+#endif
+
+ return 1;
+}
+
+/* really __gl_pqSortInsert */
+/* returns LONG_MAX iff out of memory */
+PQhandle pqInsert( PriorityQ *pq, PQkey keyNew )
+{
+ long curr;
+
+ if( pq->initialized ) {
+ return __gl_pqHeapInsert( pq->heap, keyNew );
+ }
+ curr = pq->size;
+ if( ++ pq->size >= pq->max ) {
+ PQkey *saveKey= pq->keys;
+
+ /* If the heap overflows, double its size. */
+ pq->max <<= 1;
+ pq->keys = (PQHeapKey *)memRealloc( pq->keys,
+ (size_t)
+ (pq->max * sizeof( pq->keys[0] )));
+ if (pq->keys == NULL) {
+ pq->keys = saveKey; /* restore ptr to free upon return */
+ return LONG_MAX;
+ }
+ }
+ assert(curr != LONG_MAX);
+ pq->keys[curr] = keyNew;
+
+ /* Negative handles index the sorted array. */
+ return -(curr+1);
+}
+
+/* really __gl_pqSortExtractMin */
+PQkey pqExtractMin( PriorityQ *pq )
+{
+ PQkey sortMin, heapMin;
+
+ if( pq->size == 0 ) {
+ return __gl_pqHeapExtractMin( pq->heap );
+ }
+ sortMin = *(pq->order[pq->size-1]);
+ if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+ heapMin = __gl_pqHeapMinimum( pq->heap );
+ if( LEQ( heapMin, sortMin )) {
+ return __gl_pqHeapExtractMin( pq->heap );
+ }
+ }
+ do {
+ -- pq->size;
+ } while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL );
+ return sortMin;
+}
+
+/* really __gl_pqSortMinimum */
+PQkey pqMinimum( PriorityQ *pq )
+{
+ PQkey sortMin, heapMin;
+
+ if( pq->size == 0 ) {
+ return __gl_pqHeapMinimum( pq->heap );
+ }
+ sortMin = *(pq->order[pq->size-1]);
+ if( ! __gl_pqHeapIsEmpty( pq->heap )) {
+ heapMin = __gl_pqHeapMinimum( pq->heap );
+ if( LEQ( heapMin, sortMin )) {
+ return heapMin;
+ }
+ }
+ return sortMin;
+}
+
+/* really __gl_pqSortIsEmpty */
+int pqIsEmpty( PriorityQ *pq )
+{
+ return (pq->size == 0) && __gl_pqHeapIsEmpty( pq->heap );
+}
+
+/* really __gl_pqSortDelete */
+void pqDelete( PriorityQ *pq, PQhandle curr )
+{
+ if( curr >= 0 ) {
+ __gl_pqHeapDelete( pq->heap, curr );
+ return;
+ }
+ curr = -(curr+1);
+ assert( curr < pq->max && pq->keys[curr] != NULL );
+
+ pq->keys[curr] = NULL;
+ while( pq->size > 0 && *(pq->order[pq->size-1]) == NULL ) {
+ -- pq->size;
+ }
+}
diff --git a/Source/ThirdParty/glu/libtess/priorityq.h b/Source/ThirdParty/glu/libtess/priorityq.h
new file mode 100644
index 000000000..3ae6b0c26
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/priorityq.h
@@ -0,0 +1,124 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/priorityq.h#5 $
+*/
+
+#ifndef __priorityq_sort_h_
+#define __priorityq_sort_h_
+
+#include "priorityq-heap.h"
+
+#undef PQkey
+#undef PQhandle
+#undef PriorityQ
+#undef pqNewPriorityQ
+#undef pqDeletePriorityQ
+#undef pqInit
+#undef pqInsert
+#undef pqMinimum
+#undef pqExtractMin
+#undef pqDelete
+#undef pqIsEmpty
+
+/* Use #define's so that another heap implementation can use this one */
+
+#define PQkey PQSortKey
+#define PQhandle PQSortHandle
+#define PriorityQ PriorityQSort
+
+#define pqNewPriorityQ(leq) __gl_pqSortNewPriorityQ(leq)
+#define pqDeletePriorityQ(pq) __gl_pqSortDeletePriorityQ(pq)
+
+/* The basic operations are insertion of a new key (pqInsert),
+ * and examination/extraction of a key whose value is minimum
+ * (pqMinimum/pqExtractMin). Deletion is also allowed (pqDelete);
+ * for this purpose pqInsert returns a "handle" which is supplied
+ * as the argument.
+ *
+ * An initial heap may be created efficiently by calling pqInsert
+ * repeatedly, then calling pqInit. In any case pqInit must be called
+ * before any operations other than pqInsert are used.
+ *
+ * If the heap is empty, pqMinimum/pqExtractMin will return a NULL key.
+ * This may also be tested with pqIsEmpty.
+ */
+#define pqInit(pq) __gl_pqSortInit(pq)
+#define pqInsert(pq,key) __gl_pqSortInsert(pq,key)
+#define pqMinimum(pq) __gl_pqSortMinimum(pq)
+#define pqExtractMin(pq) __gl_pqSortExtractMin(pq)
+#define pqDelete(pq,handle) __gl_pqSortDelete(pq,handle)
+#define pqIsEmpty(pq) __gl_pqSortIsEmpty(pq)
+
+
+/* Since we support deletion the data structure is a little more
+ * complicated than an ordinary heap. "nodes" is the heap itself;
+ * active nodes are stored in the range 1..pq->size. When the
+ * heap exceeds its allocated size (pq->max), its size doubles.
+ * The children of node i are nodes 2i and 2i+1.
+ *
+ * Each node stores an index into an array "handles". Each handle
+ * stores a key, plus a pointer back to the node which currently
+ * represents that key (ie. nodes[handles[i].node].handle == i).
+ */
+
+typedef PQHeapKey PQkey;
+typedef PQHeapHandle PQhandle;
+typedef struct PriorityQ PriorityQ;
+
+struct PriorityQ {
+ PriorityQHeap *heap;
+ PQkey *keys;
+ PQkey **order;
+ PQhandle size, max;
+ int initialized;
+ int (*leq)(PQkey key1, PQkey key2);
+};
+
+PriorityQ *pqNewPriorityQ( int (*leq)(PQkey key1, PQkey key2) );
+void pqDeletePriorityQ( PriorityQ *pq );
+
+int pqInit( PriorityQ *pq );
+PQhandle pqInsert( PriorityQ *pq, PQkey key );
+PQkey pqExtractMin( PriorityQ *pq );
+void pqDelete( PriorityQ *pq, PQhandle handle );
+
+PQkey pqMinimum( PriorityQ *pq );
+int pqIsEmpty( PriorityQ *pq );
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/render.c b/Source/ThirdParty/glu/libtess/render.c
new file mode 100644
index 000000000..aff129842
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/render.c
@@ -0,0 +1,505 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/render.c#5 $
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include <stddef.h>
+#include "mesh.h"
+#include "tess.h"
+#include "render.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/* This structure remembers the information we need about a primitive
+ * to be able to render it later, once we have determined which
+ * primitive is able to use the most triangles.
+ */
+struct FaceCount {
+ long size; /* number of triangles used */
+ GLUhalfEdge *eStart; /* edge where this primitive starts */
+ void (*render)(GLUtesselator *, GLUhalfEdge *, long);
+ /* routine to render this primitive */
+};
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig );
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig );
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *eStart, long size );
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *eStart,
+ long size );
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig );
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *head );
+
+
+
+/************************ Strips and Fans decomposition ******************/
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh )
+{
+ GLUface *f;
+
+ /* Make a list of separate triangles so we can render them all at once */
+ tess->lonelyTriList = NULL;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+ f->marked = FALSE;
+ }
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+
+ /* We examine all faces in an arbitrary order. Whenever we find
+ * an unprocessed face F, we output a group of faces including F
+ * whose size is maximum.
+ */
+ if( f->inside && ! f->marked ) {
+ RenderMaximumFaceGroup( tess, f );
+ assert( f->marked );
+ }
+ }
+ if( tess->lonelyTriList != NULL ) {
+ RenderLonelyTriangles( tess, tess->lonelyTriList );
+ tess->lonelyTriList = NULL;
+ }
+}
+
+
+static void RenderMaximumFaceGroup( GLUtesselator *tess, GLUface *fOrig )
+{
+ /* We want to find the largest triangle fan or strip of unmarked faces
+ * which includes the given face fOrig. There are 3 possible fans
+ * passing through fOrig (one centered at each vertex), and 3 possible
+ * strips (one for each CCW permutation of the vertices). Our strategy
+ * is to try all of these, and take the primitive which uses the most
+ * triangles (a greedy approach).
+ */
+ GLUhalfEdge *e = fOrig->anEdge;
+ struct FaceCount max, newFace;
+
+ max.size = 1;
+ max.eStart = e;
+ max.render = &RenderTriangle;
+
+ if( ! tess->flagBoundary ) {
+ newFace = MaximumFan( e ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumFan( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumFan( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+
+ newFace = MaximumStrip( e ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumStrip( e->Lnext ); if( newFace.size > max.size ) { max = newFace; }
+ newFace = MaximumStrip( e->Lprev ); if( newFace.size > max.size ) { max = newFace; }
+ }
+ (*(max.render))( tess, max.eStart, max.size );
+}
+
+
+/* Macros which keep track of faces we have marked temporarily, and allow
+ * us to backtrack when necessary. With triangle fans, this is not
+ * really necessary, since the only awkward case is a loop of triangles
+ * around a single origin vertex. However with strips the situation is
+ * more complicated, and we need a general tracking method like the
+ * one here.
+ */
+#define Marked(f) (! (f)->inside || (f)->marked)
+
+#define AddToTrail(f,t) ((f)->trail = (t), (t) = (f), (f)->marked = TRUE)
+
+#define FreeTrail(t) do { \
+ while( (t) != NULL ) { \
+ (t)->marked = FALSE; t = (t)->trail; \
+ } \
+ } while(0) /* absorb trailing semicolon */
+
+
+
+static struct FaceCount MaximumFan( GLUhalfEdge *eOrig )
+{
+ /* eOrig->Lface is the face we want to render. We want to find the size
+ * of a maximal fan around eOrig->Org. To do this we just walk around
+ * the origin vertex as far as possible in both directions.
+ */
+ struct FaceCount newFace = { 0, NULL, &RenderFan };
+ GLUface *trail = NULL;
+ GLUhalfEdge *e;
+
+ for( e = eOrig; ! Marked( e->Lface ); e = e->Onext ) {
+ AddToTrail( e->Lface, trail );
+ ++newFace.size;
+ }
+ for( e = eOrig; ! Marked( e->Rface ); e = e->Oprev ) {
+ AddToTrail( e->Rface, trail );
+ ++newFace.size;
+ }
+ newFace.eStart = e;
+ /*LINTED*/
+ FreeTrail( trail );
+ return newFace;
+}
+
+
+#define IsEven(n) (((n) & 1) == 0)
+
+static struct FaceCount MaximumStrip( GLUhalfEdge *eOrig )
+{
+ /* Here we are looking for a maximal strip that contains the vertices
+ * eOrig->Org, eOrig->Dst, eOrig->Lnext->Dst (in that order or the
+ * reverse, such that all triangles are oriented CCW).
+ *
+ * Again we walk forward and backward as far as possible. However for
+ * strips there is a twist: to get CCW orientations, there must be
+ * an *even* number of triangles in the strip on one side of eOrig.
+ * We walk the strip starting on a side with an even number of triangles;
+ * if both side have an odd number, we are forced to shorten one side.
+ */
+ struct FaceCount newFace = { 0, NULL, &RenderStrip };
+ long headSize = 0, tailSize = 0;
+ GLUface *trail = NULL;
+ GLUhalfEdge *e, *eTail, *eHead;
+
+ for( e = eOrig; ! Marked( e->Lface ); ++tailSize, e = e->Onext ) {
+ AddToTrail( e->Lface, trail );
+ ++tailSize;
+ e = e->Dprev;
+ if( Marked( e->Lface )) break;
+ AddToTrail( e->Lface, trail );
+ }
+ eTail = e;
+
+ for( e = eOrig; ! Marked( e->Rface ); ++headSize, e = e->Dnext ) {
+ AddToTrail( e->Rface, trail );
+ ++headSize;
+ e = e->Oprev;
+ if( Marked( e->Rface )) break;
+ AddToTrail( e->Rface, trail );
+ }
+ eHead = e;
+
+ newFace.size = tailSize + headSize;
+ if( IsEven( tailSize )) {
+ newFace.eStart = eTail->Sym;
+ } else if( IsEven( headSize )) {
+ newFace.eStart = eHead;
+ } else {
+ /* Both sides have odd length, we must shorten one of them. In fact,
+ * we must start from eHead to guarantee inclusion of eOrig->Lface.
+ */
+ --newFace.size;
+ newFace.eStart = eHead->Onext;
+ }
+ /*LINTED*/
+ FreeTrail( trail );
+ return newFace;
+}
+
+
+static void RenderTriangle( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Just add the triangle to a triangle list, so we can render all
+ * the separate triangles at once.
+ */
+ assert( size == 1 );
+ AddToTrail( e->Lface, tess->lonelyTriList );
+}
+
+
+static void RenderLonelyTriangles( GLUtesselator *tess, GLUface *f )
+{
+ /* Now we render all the separate triangles which could not be
+ * grouped into a triangle fan or strip.
+ */
+ GLUhalfEdge *e;
+ int newState;
+ int edgeState = -1; /* force edge state output for first vertex */
+
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLES );
+
+ for( ; f != NULL; f = f->trail ) {
+ /* Loop once for each edge (there will always be 3 edges) */
+
+ e = f->anEdge;
+ do {
+ if( tess->flagBoundary ) {
+ /* Set the "edge state" to TRUE just before we output the
+ * first vertex of each edge on the polygon boundary.
+ */
+ newState = ! e->Rface->inside;
+ if( edgeState != newState ) {
+ edgeState = newState;
+ CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA( edgeState );
+ }
+ }
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ }
+ CALL_END_OR_END_DATA();
+}
+
+
+static void RenderFan( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Render as many CCW triangles as possible in a fan starting from
+ * edge "e". The fan *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_FAN );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+
+ while( ! Marked( e->Lface )) {
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Onext;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+ }
+
+ assert( size == 0 );
+ CALL_END_OR_END_DATA();
+}
+
+
+static void RenderStrip( GLUtesselator *tess, GLUhalfEdge *e, long size )
+{
+ /* Render as many CCW triangles as possible in a strip starting from
+ * edge "e". The strip *should* contain exactly "size" triangles
+ * (otherwise we've goofed up somewhere).
+ */
+ CALL_BEGIN_OR_BEGIN_DATA( GL_TRIANGLE_STRIP );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+
+ while( ! Marked( e->Lface )) {
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Dprev;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ if( Marked( e->Lface )) break;
+
+ e->Lface->marked = TRUE;
+ --size;
+ e = e->Onext;
+ CALL_VERTEX_OR_VERTEX_DATA( e->Dst->data );
+ }
+
+ assert( size == 0 );
+ CALL_END_OR_END_DATA();
+}
+
+
+/************************ Boundary contour decomposition ******************/
+
+/* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one
+ * contour for each face marked "inside". The rendering output is
+ * provided as callbacks (see the api).
+ */
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh )
+{
+ GLUface *f;
+ GLUhalfEdge *e;
+
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = f->next ) {
+ if( f->inside ) {
+ CALL_BEGIN_OR_BEGIN_DATA( GL_LINE_LOOP );
+ e = f->anEdge;
+ do {
+ CALL_VERTEX_OR_VERTEX_DATA( e->Org->data );
+ e = e->Lnext;
+ } while( e != f->anEdge );
+ CALL_END_OR_END_DATA();
+ }
+ }
+}
+
+
+/************************ Quick-and-dirty decomposition ******************/
+
+#define SIGN_INCONSISTENT 2
+
+static int ComputeNormal( GLUtesselator *tess, GLdouble norm[3], int check )
+/*
+ * If check==FALSE, we compute the polygon normal and place it in norm[].
+ * If check==TRUE, we check that each triangle in the fan from v0 has a
+ * consistent orientation with respect to norm[]. If triangles are
+ * consistently oriented CCW, return 1; if CW, return -1; if all triangles
+ * are degenerate return 0; otherwise (no consistent orientation) return
+ * SIGN_INCONSISTENT.
+ */
+{
+ CachedVertex *v0 = tess->cache;
+ CachedVertex *vn = v0 + tess->cacheCount;
+ CachedVertex *vc;
+ GLdouble dot, xc, yc, zc, xp, yp, zp, n[3];
+ int sign = 0;
+
+ /* Find the polygon normal. It is important to get a reasonable
+ * normal even when the polygon is self-intersecting (eg. a bowtie).
+ * Otherwise, the computed normal could be very tiny, but perpendicular
+ * to the true plane of the polygon due to numerical noise. Then all
+ * the triangles would appear to be degenerate and we would incorrectly
+ * decompose the polygon as a fan (or simply not render it at all).
+ *
+ * We use a sum-of-triangles normal algorithm rather than the more
+ * efficient sum-of-trapezoids method (used in CheckOrientation()
+ * in normal.c). This lets us explicitly reverse the signed area
+ * of some triangles to get a reasonable normal in the self-intersecting
+ * case.
+ */
+ if( ! check ) {
+ norm[0] = norm[1] = norm[2] = 0.0;
+ }
+
+ vc = v0 + 1;
+ xc = vc->coords[0] - v0->coords[0];
+ yc = vc->coords[1] - v0->coords[1];
+ zc = vc->coords[2] - v0->coords[2];
+ while( ++vc < vn ) {
+ xp = xc; yp = yc; zp = zc;
+ xc = vc->coords[0] - v0->coords[0];
+ yc = vc->coords[1] - v0->coords[1];
+ zc = vc->coords[2] - v0->coords[2];
+
+ /* Compute (vp - v0) cross (vc - v0) */
+ n[0] = yp*zc - zp*yc;
+ n[1] = zp*xc - xp*zc;
+ n[2] = xp*yc - yp*xc;
+
+ dot = n[0]*norm[0] + n[1]*norm[1] + n[2]*norm[2];
+ if( ! check ) {
+ /* Reverse the contribution of back-facing triangles to get
+ * a reasonable normal for self-intersecting polygons (see above)
+ */
+ if( dot >= 0 ) {
+ norm[0] += n[0]; norm[1] += n[1]; norm[2] += n[2];
+ } else {
+ norm[0] -= n[0]; norm[1] -= n[1]; norm[2] -= n[2];
+ }
+ } else if( dot != 0 ) {
+ /* Check the new orientation for consistency with previous triangles */
+ if( dot > 0 ) {
+ if( sign < 0 ) return SIGN_INCONSISTENT;
+ sign = 1;
+ } else {
+ if( sign > 0 ) return SIGN_INCONSISTENT;
+ sign = -1;
+ }
+ }
+ }
+ return sign;
+}
+
+/* __gl_renderCache( tess ) takes a single contour and tries to render it
+ * as a triangle fan. This handles convex polygons, as well as some
+ * non-convex polygons if we get lucky.
+ *
+ * Returns TRUE if the polygon was successfully rendered. The rendering
+ * output is provided as callbacks (see the api).
+ */
+GLboolean __gl_renderCache( GLUtesselator *tess )
+{
+ CachedVertex *v0 = tess->cache;
+ CachedVertex *vn = v0 + tess->cacheCount;
+ CachedVertex *vc;
+ GLdouble norm[3];
+ int sign;
+
+ if( tess->cacheCount < 3 ) {
+ /* Degenerate contour -- no output */
+ return TRUE;
+ }
+
+ norm[0] = tess->normal[0];
+ norm[1] = tess->normal[1];
+ norm[2] = tess->normal[2];
+ if( norm[0] == 0 && norm[1] == 0 && norm[2] == 0 ) {
+ ComputeNormal( tess, norm, FALSE );
+ }
+
+ sign = ComputeNormal( tess, norm, TRUE );
+ if( sign == SIGN_INCONSISTENT ) {
+ /* Fan triangles did not have a consistent orientation */
+ return FALSE;
+ }
+ if( sign == 0 ) {
+ /* All triangles were degenerate */
+ return TRUE;
+ }
+
+ /* Make sure we do the right thing for each winding rule */
+ switch( tess->windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ break;
+ case GLU_TESS_WINDING_POSITIVE:
+ if( sign < 0 ) return TRUE;
+ break;
+ case GLU_TESS_WINDING_NEGATIVE:
+ if( sign > 0 ) return TRUE;
+ break;
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return TRUE;
+ }
+
+ CALL_BEGIN_OR_BEGIN_DATA( tess->boundaryOnly ? GL_LINE_LOOP
+ : (tess->cacheCount > 3) ? GL_TRIANGLE_FAN
+ : GL_TRIANGLES );
+
+ CALL_VERTEX_OR_VERTEX_DATA( v0->data );
+ if( sign > 0 ) {
+ for( vc = v0+1; vc < vn; ++vc ) {
+ CALL_VERTEX_OR_VERTEX_DATA( vc->data );
+ }
+ } else {
+ for( vc = vn-1; vc > v0; --vc ) {
+ CALL_VERTEX_OR_VERTEX_DATA( vc->data );
+ }
+ }
+ CALL_END_OR_END_DATA();
+ return TRUE;
+}
diff --git a/Source/ThirdParty/glu/libtess/render.h b/Source/ThirdParty/glu/libtess/render.h
new file mode 100644
index 000000000..598423ea0
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/render.h
@@ -0,0 +1,59 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/render.h#5 $
+*/
+
+#ifndef __render_h_
+#define __render_h_
+
+#include "mesh.h"
+
+/* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
+ * fans, strips, and separate triangles. A substantial effort is made
+ * to use as few rendering primitives as possible (ie. to make the fans
+ * and strips as large as possible).
+ *
+ * The rendering output is provided as callbacks (see the api).
+ */
+void __gl_renderMesh( GLUtesselator *tess, GLUmesh *mesh );
+void __gl_renderBoundary( GLUtesselator *tess, GLUmesh *mesh );
+
+GLboolean __gl_renderCache( GLUtesselator *tess );
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/sweep.c b/Source/ThirdParty/glu/libtess/sweep.c
new file mode 100644
index 000000000..6fe8a478f
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/sweep.c
@@ -0,0 +1,1362 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/sweep.c#5 $
+*/
+
+#include "gluos.h"
+#include <assert.h>
+#include <stddef.h>
+#include <setjmp.h> /* longjmp */
+#include <limits.h> /* LONG_MAX */
+
+#include "mesh.h"
+#include "geom.h"
+#include "tess.h"
+#include "dict.h"
+#include "priorityq.h"
+#include "memalloc.h"
+#include "sweep.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#ifdef FOR_TRITE_TEST_PROGRAM
+extern void DebugEvent( GLUtesselator *tess );
+#else
+#define DebugEvent( tess )
+#endif
+
+/*
+ * Invariants for the Edge Dictionary.
+ * - each pair of adjacent edges e2=Succ(e1) satisfies EdgeLeq(e1,e2)
+ * at any valid location of the sweep event
+ * - if EdgeLeq(e2,e1) as well (at any valid sweep event), then e1 and e2
+ * share a common endpoint
+ * - for each e, e->Dst has been processed, but not e->Org
+ * - each edge e satisfies VertLeq(e->Dst,event) && VertLeq(event,e->Org)
+ * where "event" is the current sweep line event.
+ * - no edge e has zero length
+ *
+ * Invariants for the Mesh (the processed portion).
+ * - the portion of the mesh left of the sweep line is a planar graph,
+ * ie. there is *some* way to embed it in the plane
+ * - no processed edge has zero length
+ * - no two processed vertices have identical coordinates
+ * - each "inside" region is monotone, ie. can be broken into two chains
+ * of monotonically increasing vertices according to VertLeq(v1,v2)
+ * - a non-invariant: these chains may intersect (very slightly)
+ *
+ * Invariants for the Sweep.
+ * - if none of the edges incident to the event vertex have an activeRegion
+ * (ie. none of these edges are in the edge dictionary), then the vertex
+ * has only right-going edges.
+ * - if an edge is marked "fixUpperEdge" (it is a temporary edge introduced
+ * by ConnectRightVertex), then it is the only right-going edge from
+ * its associated vertex. (This says that these edges exist only
+ * when it is necessary.)
+ */
+
+#define MAX(x,y) ((x) >= (y) ? (x) : (y))
+#define MIN(x,y) ((x) <= (y) ? (x) : (y))
+
+/* When we merge two edges into one, we need to compute the combined
+ * winding of the new edge.
+ */
+#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
+ eDst->Sym->winding += eSrc->Sym->winding)
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent );
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp );
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp );
+
+static int EdgeLeq( GLUtesselator *tess, ActiveRegion *reg1,
+ ActiveRegion *reg2 )
+/*
+ * Both edges must be directed from right to left (this is the canonical
+ * direction for the upper edge of each region).
+ *
+ * The strategy is to evaluate a "t" value for each edge at the
+ * current sweep line position, given by tess->event. The calculations
+ * are designed to be very stable, but of course they are not perfect.
+ *
+ * Special case: if both edge destinations are at the sweep event,
+ * we sort the edges by slope (they would otherwise compare equally).
+ */
+{
+ GLUvertex *event = tess->event;
+ GLUhalfEdge *e1, *e2;
+ GLdouble t1, t2;
+
+ e1 = reg1->eUp;
+ e2 = reg2->eUp;
+
+ if( e1->Dst == event ) {
+ if( e2->Dst == event ) {
+ /* Two edges right of the sweep line which meet at the sweep event.
+ * Sort them by slope.
+ */
+ if( VertLeq( e1->Org, e2->Org )) {
+ return EdgeSign( e2->Dst, e1->Org, e2->Org ) <= 0;
+ }
+ return EdgeSign( e1->Dst, e2->Org, e1->Org ) >= 0;
+ }
+ return EdgeSign( e2->Dst, event, e2->Org ) <= 0;
+ }
+ if( e2->Dst == event ) {
+ return EdgeSign( e1->Dst, event, e1->Org ) >= 0;
+ }
+
+ /* General case - compute signed distance *from* e1, e2 to event */
+ t1 = EdgeEval( e1->Dst, event, e1->Org );
+ t2 = EdgeEval( e2->Dst, event, e2->Org );
+ return (t1 >= t2);
+}
+
+
+static void DeleteRegion( GLUtesselator *tess, ActiveRegion *reg )
+{
+ if( reg->fixUpperEdge ) {
+ /* It was created with zero winding number, so it better be
+ * deleted with zero winding number (ie. it better not get merged
+ * with a real edge).
+ */
+ assert( reg->eUp->winding == 0 );
+ }
+ reg->eUp->activeRegion = NULL;
+ dictDelete( tess->dict, reg->nodeUp ); /* __gl_dictListDelete */
+ memFree( reg );
+}
+
+
+static int FixUpperEdge( ActiveRegion *reg, GLUhalfEdge *newEdge )
+/*
+ * Replace an upper edge which needs fixing (see ConnectRightVertex).
+ */
+{
+ assert( reg->fixUpperEdge );
+ if ( !__gl_meshDelete( reg->eUp ) ) return 0;
+ reg->fixUpperEdge = FALSE;
+ reg->eUp = newEdge;
+ newEdge->activeRegion = reg;
+
+ return 1;
+}
+
+static ActiveRegion *TopLeftRegion( ActiveRegion *reg )
+{
+ GLUvertex *org = reg->eUp->Org;
+ GLUhalfEdge *e;
+
+ /* Find the region above the uppermost edge with the same origin */
+ do {
+ reg = RegionAbove( reg );
+ } while( reg->eUp->Org == org );
+
+ /* If the edge above was a temporary edge introduced by ConnectRightVertex,
+ * now is the time to fix it.
+ */
+ if( reg->fixUpperEdge ) {
+ e = __gl_meshConnect( RegionBelow(reg)->eUp->Sym, reg->eUp->Lnext );
+ if (e == NULL) return NULL;
+ if ( !FixUpperEdge( reg, e ) ) return NULL;
+ reg = RegionAbove( reg );
+ }
+ return reg;
+}
+
+static ActiveRegion *TopRightRegion( ActiveRegion *reg )
+{
+ GLUvertex *dst = reg->eUp->Dst;
+
+ /* Find the region above the uppermost edge with the same destination */
+ do {
+ reg = RegionAbove( reg );
+ } while( reg->eUp->Dst == dst );
+ return reg;
+}
+
+static ActiveRegion *AddRegionBelow( GLUtesselator *tess,
+ ActiveRegion *regAbove,
+ GLUhalfEdge *eNewUp )
+/*
+ * Add a new active region to the sweep line, *somewhere* below "regAbove"
+ * (according to where the new edge belongs in the sweep-line dictionary).
+ * The upper edge of the new region will be "eNewUp".
+ * Winding number and "inside" flag are not updated.
+ */
+{
+ ActiveRegion *regNew = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+ if (regNew == NULL) longjmp(tess->env,1);
+
+ regNew->eUp = eNewUp;
+ /* __gl_dictListInsertBefore */
+ regNew->nodeUp = dictInsertBefore( tess->dict, regAbove->nodeUp, regNew );
+ if (regNew->nodeUp == NULL) longjmp(tess->env,1);
+ regNew->fixUpperEdge = FALSE;
+ regNew->sentinel = FALSE;
+ regNew->dirty = FALSE;
+
+ eNewUp->activeRegion = regNew;
+ return regNew;
+}
+
+static GLboolean IsWindingInside( GLUtesselator *tess, int n )
+{
+ switch( tess->windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ return (n & 1);
+ case GLU_TESS_WINDING_NONZERO:
+ return (n != 0);
+ case GLU_TESS_WINDING_POSITIVE:
+ return (n > 0);
+ case GLU_TESS_WINDING_NEGATIVE:
+ return (n < 0);
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ return (n >= 2) || (n <= -2);
+ }
+ /*LINTED*/
+ assert( FALSE );
+ /*NOTREACHED*/
+ return 0;
+}
+
+
+static void ComputeWinding( GLUtesselator *tess, ActiveRegion *reg )
+{
+ reg->windingNumber = RegionAbove(reg)->windingNumber + reg->eUp->winding;
+ reg->inside = IsWindingInside( tess, reg->windingNumber );
+}
+
+
+static void FinishRegion( GLUtesselator *tess, ActiveRegion *reg )
+/*
+ * Delete a region from the sweep line. This happens when the upper
+ * and lower chains of a region meet (at a vertex on the sweep line).
+ * The "inside" flag is copied to the appropriate mesh face (we could
+ * not do this before -- since the structure of the mesh is always
+ * changing, this face may not have even existed until now).
+ */
+{
+ GLUhalfEdge *e = reg->eUp;
+ GLUface *f = e->Lface;
+
+ f->inside = reg->inside;
+ f->anEdge = e; /* optimization for __gl_meshTessellateMonoRegion() */
+ DeleteRegion( tess, reg );
+}
+
+
+static GLUhalfEdge *FinishLeftRegions( GLUtesselator *tess,
+ ActiveRegion *regFirst, ActiveRegion *regLast )
+/*
+ * We are given a vertex with one or more left-going edges. All affected
+ * edges should be in the edge dictionary. Starting at regFirst->eUp,
+ * we walk down deleting all regions where both edges have the same
+ * origin vOrg. At the same time we copy the "inside" flag from the
+ * active region to the face, since at this point each face will belong
+ * to at most one region (this was not necessarily true until this point
+ * in the sweep). The walk stops at the region above regLast; if regLast
+ * is NULL we walk as far as possible. At the same time we relink the
+ * mesh if necessary, so that the ordering of edges around vOrg is the
+ * same as in the dictionary.
+ */
+{
+ ActiveRegion *reg, *regPrev;
+ GLUhalfEdge *e, *ePrev;
+
+ regPrev = regFirst;
+ ePrev = regFirst->eUp;
+ while( regPrev != regLast ) {
+ regPrev->fixUpperEdge = FALSE; /* placement was OK */
+ reg = RegionBelow( regPrev );
+ e = reg->eUp;
+ if( e->Org != ePrev->Org ) {
+ if( ! reg->fixUpperEdge ) {
+ /* Remove the last left-going edge. Even though there are no further
+ * edges in the dictionary with this origin, there may be further
+ * such edges in the mesh (if we are adding left edges to a vertex
+ * that has already been processed). Thus it is important to call
+ * FinishRegion rather than just DeleteRegion.
+ */
+ FinishRegion( tess, regPrev );
+ break;
+ }
+ /* If the edge below was a temporary edge introduced by
+ * ConnectRightVertex, now is the time to fix it.
+ */
+ e = __gl_meshConnect( ePrev->Lprev, e->Sym );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !FixUpperEdge( reg, e ) ) longjmp(tess->env,1);
+ }
+
+ /* Relink edges so that ePrev->Onext == e */
+ if( ePrev->Onext != e ) {
+ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( ePrev, e ) ) longjmp(tess->env,1);
+ }
+ FinishRegion( tess, regPrev ); /* may change reg->eUp */
+ ePrev = reg->eUp;
+ regPrev = reg;
+ }
+ return ePrev;
+}
+
+
+static void AddRightEdges( GLUtesselator *tess, ActiveRegion *regUp,
+ GLUhalfEdge *eFirst, GLUhalfEdge *eLast, GLUhalfEdge *eTopLeft,
+ GLboolean cleanUp )
+/*
+ * Purpose: insert right-going edges into the edge dictionary, and update
+ * winding numbers and mesh connectivity appropriately. All right-going
+ * edges share a common origin vOrg. Edges are inserted CCW starting at
+ * eFirst; the last edge inserted is eLast->Oprev. If vOrg has any
+ * left-going edges already processed, then eTopLeft must be the edge
+ * such that an imaginary upward vertical segment from vOrg would be
+ * contained between eTopLeft->Oprev and eTopLeft; otherwise eTopLeft
+ * should be NULL.
+ */
+{
+ ActiveRegion *reg, *regPrev;
+ GLUhalfEdge *e, *ePrev;
+ int firstTime = TRUE;
+
+ /* Insert the new right-going edges in the dictionary */
+ e = eFirst;
+ do {
+ assert( VertLeq( e->Org, e->Dst ));
+ AddRegionBelow( tess, regUp, e->Sym );
+ e = e->Onext;
+ } while ( e != eLast );
+
+ /* Walk *all* right-going edges from e->Org, in the dictionary order,
+ * updating the winding numbers of each region, and re-linking the mesh
+ * edges to match the dictionary ordering (if necessary).
+ */
+ if( eTopLeft == NULL ) {
+ eTopLeft = RegionBelow( regUp )->eUp->Rprev;
+ }
+ regPrev = regUp;
+ ePrev = eTopLeft;
+ for( ;; ) {
+ reg = RegionBelow( regPrev );
+ e = reg->eUp->Sym;
+ if( e->Org != ePrev->Org ) break;
+
+ if( e->Onext != ePrev ) {
+ /* Unlink e from its current position, and relink below ePrev */
+ if ( !__gl_meshSplice( e->Oprev, e ) ) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( ePrev->Oprev, e ) ) longjmp(tess->env,1);
+ }
+ /* Compute the winding number and "inside" flag for the new regions */
+ reg->windingNumber = regPrev->windingNumber - e->winding;
+ reg->inside = IsWindingInside( tess, reg->windingNumber );
+
+ /* Check for two outgoing edges with same slope -- process these
+ * before any intersection tests (see example in __gl_computeInterior).
+ */
+ regPrev->dirty = TRUE;
+ if( ! firstTime && CheckForRightSplice( tess, regPrev )) {
+ AddWinding( e, ePrev );
+ DeleteRegion( tess, regPrev );
+ if ( !__gl_meshDelete( ePrev ) ) longjmp(tess->env,1);
+ }
+ firstTime = FALSE;
+ regPrev = reg;
+ ePrev = e;
+ }
+ regPrev->dirty = TRUE;
+ assert( regPrev->windingNumber - e->winding == reg->windingNumber );
+
+ if( cleanUp ) {
+ /* Check for intersections between newly adjacent edges. */
+ WalkDirtyRegions( tess, regPrev );
+ }
+}
+
+
+static void CallCombine( GLUtesselator *tess, GLUvertex *isect,
+ void *data[4], GLfloat weights[4], int needed )
+{
+ GLdouble coords[3];
+
+ /* Copy coord data in case the callback changes it. */
+ coords[0] = isect->coords[0];
+ coords[1] = isect->coords[1];
+ coords[2] = isect->coords[2];
+
+ isect->data = NULL;
+ CALL_COMBINE_OR_COMBINE_DATA( coords, data, weights, &isect->data );
+ if( isect->data == NULL ) {
+ if( ! needed ) {
+ isect->data = data[0];
+ } else if( ! tess->fatalError ) {
+ /* The only way fatal error is when two edges are found to intersect,
+ * but the user has not provided the callback necessary to handle
+ * generated intersection points.
+ */
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_NEED_COMBINE_CALLBACK );
+ tess->fatalError = TRUE;
+ }
+ }
+}
+
+static void SpliceMergeVertices( GLUtesselator *tess, GLUhalfEdge *e1,
+ GLUhalfEdge *e2 )
+/*
+ * Two vertices with idential coordinates are combined into one.
+ * e1->Org is kept, while e2->Org is discarded.
+ */
+{
+ void *data[4] = { NULL, NULL, NULL, NULL };
+ GLfloat weights[4] = { 0.5, 0.5, 0.0, 0.0 };
+
+ data[0] = e1->Org->data;
+ data[1] = e2->Org->data;
+ CallCombine( tess, e1->Org, data, weights, FALSE );
+ if ( !__gl_meshSplice( e1, e2 ) ) longjmp(tess->env,1);
+}
+
+static void VertexWeights( GLUvertex *isect, GLUvertex *org, GLUvertex *dst,
+ GLfloat *weights )
+/*
+ * Find some weights which describe how the intersection vertex is
+ * a linear combination of "org" and "dest". Each of the two edges
+ * which generated "isect" is allocated 50% of the weight; each edge
+ * splits the weight between its org and dst according to the
+ * relative distance to "isect".
+ */
+{
+ GLdouble t1 = VertL1dist( org, isect );
+ GLdouble t2 = VertL1dist( dst, isect );
+
+ weights[0] = 0.5 * t2 / (t1 + t2);
+ weights[1] = 0.5 * t1 / (t1 + t2);
+ isect->coords[0] += weights[0]*org->coords[0] + weights[1]*dst->coords[0];
+ isect->coords[1] += weights[0]*org->coords[1] + weights[1]*dst->coords[1];
+ isect->coords[2] += weights[0]*org->coords[2] + weights[1]*dst->coords[2];
+}
+
+
+static void GetIntersectData( GLUtesselator *tess, GLUvertex *isect,
+ GLUvertex *orgUp, GLUvertex *dstUp,
+ GLUvertex *orgLo, GLUvertex *dstLo )
+/*
+ * We've computed a new intersection point, now we need a "data" pointer
+ * from the user so that we can refer to this new vertex in the
+ * rendering callbacks.
+ */
+{
+ void *data[4];
+ GLfloat weights[4];
+
+ data[0] = orgUp->data;
+ data[1] = dstUp->data;
+ data[2] = orgLo->data;
+ data[3] = dstLo->data;
+
+ isect->coords[0] = isect->coords[1] = isect->coords[2] = 0;
+ VertexWeights( isect, orgUp, dstUp, &weights[0] );
+ VertexWeights( isect, orgLo, dstLo, &weights[2] );
+
+ CallCombine( tess, isect, data, weights, TRUE );
+}
+
+static int CheckForRightSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Org is above eLo, or eLo->Org is below eUp (depending on which
+ * origin is leftmost).
+ *
+ * The main purpose is to splice right-going edges with the same
+ * dest vertex and nearly identical slopes (ie. we can't distinguish
+ * the slopes numerically). However the splicing can also help us
+ * to recover from numerical errors. For example, suppose at one
+ * point we checked eUp and eLo, and decided that eUp->Org is barely
+ * above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * our test so that now eUp->Org is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants.
+ *
+ * One possibility is to check these edges for intersection again
+ * (ie. CheckForIntersect). This is what we do if possible. However
+ * CheckForIntersect requires that tess->event lies between eUp and eLo,
+ * so that it has something to fall back on when the intersection
+ * calculation gives us an unusable answer. So, for those cases where
+ * we can't check for intersection, this routine fixes the problem
+ * by just splicing the offending vertex into the other edge.
+ * This is a guaranteed solution, no matter how degenerate things get.
+ * Basically this is a combinatorial solution to a numerical problem.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+
+ if( VertLeq( eUp->Org, eLo->Org )) {
+ if( EdgeSign( eLo->Dst, eUp->Org, eLo->Org ) > 0 ) return FALSE;
+
+ /* eUp->Org appears to be below eLo */
+ if( ! VertEq( eUp->Org, eLo->Org )) {
+ /* Splice eUp->Org into eLo */
+ if ( __gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp, eLo->Oprev ) ) longjmp(tess->env,1);
+ regUp->dirty = regLo->dirty = TRUE;
+
+ } else if( eUp->Org != eLo->Org ) {
+ /* merge the two vertices, discarding eUp->Org */
+ pqDelete( tess->pq, eUp->Org->pqHandle ); /* __gl_pqSortDelete */
+ SpliceMergeVertices( tess, eLo->Oprev, eUp );
+ }
+ } else {
+ if( EdgeSign( eUp->Dst, eLo->Org, eUp->Org ) < 0 ) return FALSE;
+
+ /* eLo->Org appears to be above eUp, so splice eLo->Org into eUp */
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+ }
+ return TRUE;
+}
+
+static int CheckForLeftSplice( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edge of "regUp", to make sure that the
+ * eUp->Dst is above eLo, or eLo->Dst is below eUp (depending on which
+ * destination is rightmost).
+ *
+ * Theoretically, this should always be true. However, splitting an edge
+ * into two pieces can change the results of previous tests. For example,
+ * suppose at one point we checked eUp and eLo, and decided that eUp->Dst
+ * is barely above eLo. Then later, we split eLo into two edges (eg. from
+ * a splice operation like this one). This can change the result of
+ * the test so that now eUp->Dst is incident to eLo, or barely below it.
+ * We must correct this condition to maintain the dictionary invariants
+ * (otherwise new edges might get inserted in the wrong place in the
+ * dictionary, and bad stuff will happen).
+ *
+ * We fix the problem by just splicing the offending vertex into the
+ * other edge.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ GLUhalfEdge *e;
+
+ assert( ! VertEq( eUp->Dst, eLo->Dst ));
+
+ if( VertLeq( eUp->Dst, eLo->Dst )) {
+ if( EdgeSign( eUp->Dst, eLo->Dst, eUp->Org ) < 0 ) return FALSE;
+
+ /* eLo->Dst is above eUp, so splice eLo->Dst into eUp */
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ e = __gl_meshSplitEdge( eUp );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Sym, e ) ) longjmp(tess->env,1);
+ e->Lface->inside = regUp->inside;
+ } else {
+ if( EdgeSign( eLo->Dst, eUp->Dst, eLo->Org ) > 0 ) return FALSE;
+
+ /* eUp->Dst is below eLo, so splice eUp->Dst into eLo */
+ regUp->dirty = regLo->dirty = TRUE;
+ e = __gl_meshSplitEdge( eLo );
+ if (e == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp->Lnext, eLo->Sym ) ) longjmp(tess->env,1);
+ e->Rface->inside = regUp->inside;
+ }
+ return TRUE;
+}
+
+
+static int CheckForIntersect( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * Check the upper and lower edges of the given region to see if
+ * they intersect. If so, create the intersection and add it
+ * to the data structures.
+ *
+ * Returns TRUE if adding the new intersection resulted in a recursive
+ * call to AddRightEdges(); in this case all "dirty" regions have been
+ * checked for intersections, and possibly regUp has been deleted.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ GLUvertex *orgUp = eUp->Org;
+ GLUvertex *orgLo = eLo->Org;
+ GLUvertex *dstUp = eUp->Dst;
+ GLUvertex *dstLo = eLo->Dst;
+ GLdouble tMinUp, tMaxLo;
+ GLUvertex isect, *orgMin;
+ GLUhalfEdge *e;
+
+ assert( ! VertEq( dstLo, dstUp ));
+ assert( EdgeSign( dstUp, tess->event, orgUp ) <= 0 );
+ assert( EdgeSign( dstLo, tess->event, orgLo ) >= 0 );
+ assert( orgUp != tess->event && orgLo != tess->event );
+ assert( ! regUp->fixUpperEdge && ! regLo->fixUpperEdge );
+
+ if( orgUp == orgLo ) return FALSE; /* right endpoints are the same */
+
+ tMinUp = MIN( orgUp->t, dstUp->t );
+ tMaxLo = MAX( orgLo->t, dstLo->t );
+ if( tMinUp > tMaxLo ) return FALSE; /* t ranges do not overlap */
+
+ if( VertLeq( orgUp, orgLo )) {
+ if( EdgeSign( dstLo, orgUp, orgLo ) > 0 ) return FALSE;
+ } else {
+ if( EdgeSign( dstUp, orgLo, orgUp ) < 0 ) return FALSE;
+ }
+
+ /* At this point the edges intersect, at least marginally */
+ DebugEvent( tess );
+
+ __gl_edgeIntersect( dstUp, orgUp, dstLo, orgLo, &isect );
+ /* The following properties are guaranteed: */
+ assert( MIN( orgUp->t, dstUp->t ) <= isect.t );
+ assert( isect.t <= MAX( orgLo->t, dstLo->t ));
+ assert( MIN( dstLo->s, dstUp->s ) <= isect.s );
+ assert( isect.s <= MAX( orgLo->s, orgUp->s ));
+
+ if( VertLeq( &isect, tess->event )) {
+ /* The intersection point lies slightly to the left of the sweep line,
+ * so move it until it''s slightly to the right of the sweep line.
+ * (If we had perfect numerical precision, this would never happen
+ * in the first place). The easiest and safest thing to do is
+ * replace the intersection by tess->event.
+ */
+ isect.s = tess->event->s;
+ isect.t = tess->event->t;
+ }
+ /* Similarly, if the computed intersection lies to the right of the
+ * rightmost origin (which should rarely happen), it can cause
+ * unbelievable inefficiency on sufficiently degenerate inputs.
+ * (If you have the test program, try running test54.d with the
+ * "X zoom" option turned on).
+ */
+ orgMin = VertLeq( orgUp, orgLo ) ? orgUp : orgLo;
+ if( VertLeq( orgMin, &isect )) {
+ isect.s = orgMin->s;
+ isect.t = orgMin->t;
+ }
+
+ if( VertEq( &isect, orgUp ) || VertEq( &isect, orgLo )) {
+ /* Easy case -- intersection at one of the right endpoints */
+ (void) CheckForRightSplice( tess, regUp );
+ return FALSE;
+ }
+
+ if( (! VertEq( dstUp, tess->event )
+ && EdgeSign( dstUp, tess->event, &isect ) >= 0)
+ || (! VertEq( dstLo, tess->event )
+ && EdgeSign( dstLo, tess->event, &isect ) <= 0 ))
+ {
+ /* Very unusual -- the new upper or lower edge would pass on the
+ * wrong side of the sweep event, or through it. This can happen
+ * due to very small numerical errors in the intersection calculation.
+ */
+ if( dstLo == tess->event ) {
+ /* Splice dstLo into eUp, and process the new region(s) */
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Sym, eUp ) ) longjmp(tess->env,1);
+ regUp = TopLeftRegion( regUp );
+ if (regUp == NULL) longjmp(tess->env,1);
+ eUp = RegionBelow(regUp)->eUp;
+ FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+ AddRightEdges( tess, regUp, eUp->Oprev, eUp, eUp, TRUE );
+ return TRUE;
+ }
+ if( dstUp == tess->event ) {
+ /* Splice dstUp into eLo, and process the new region(s) */
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eUp->Lnext, eLo->Oprev ) ) longjmp(tess->env,1);
+ regLo = regUp;
+ regUp = TopRightRegion( regUp );
+ e = RegionBelow(regUp)->eUp->Rprev;
+ regLo->eUp = eLo->Oprev;
+ eLo = FinishLeftRegions( tess, regLo, NULL );
+ AddRightEdges( tess, regUp, eLo->Onext, eUp->Rprev, e, TRUE );
+ return TRUE;
+ }
+ /* Special case: called from ConnectRightVertex. If either
+ * edge passes on the wrong side of tess->event, split it
+ * (and wait for ConnectRightVertex to splice it appropriately).
+ */
+ if( EdgeSign( dstUp, tess->event, &isect ) >= 0 ) {
+ RegionAbove(regUp)->dirty = regUp->dirty = TRUE;
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ eUp->Org->s = tess->event->s;
+ eUp->Org->t = tess->event->t;
+ }
+ if( EdgeSign( dstLo, tess->event, &isect ) <= 0 ) {
+ regUp->dirty = regLo->dirty = TRUE;
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ eLo->Org->s = tess->event->s;
+ eLo->Org->t = tess->event->t;
+ }
+ /* leave the rest for ConnectRightVertex */
+ return FALSE;
+ }
+
+ /* General case -- split both edges, splice into new vertex.
+ * When we do the splice operation, the order of the arguments is
+ * arbitrary as far as correctness goes. However, when the operation
+ * creates a new face, the work done is proportional to the size of
+ * the new face. We expect the faces in the processed part of
+ * the mesh (ie. eUp->Lface) to be smaller than the faces in the
+ * unprocessed original contours (which will be eLo->Oprev->Lface).
+ */
+ if (__gl_meshSplitEdge( eUp->Sym ) == NULL) longjmp(tess->env,1);
+ if (__gl_meshSplitEdge( eLo->Sym ) == NULL) longjmp(tess->env,1);
+ if ( !__gl_meshSplice( eLo->Oprev, eUp ) ) longjmp(tess->env,1);
+ eUp->Org->s = isect.s;
+ eUp->Org->t = isect.t;
+ eUp->Org->pqHandle = pqInsert( tess->pq, eUp->Org ); /* __gl_pqSortInsert */
+ if (eUp->Org->pqHandle == LONG_MAX) {
+ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */
+ tess->pq = NULL;
+ longjmp(tess->env,1);
+ }
+ GetIntersectData( tess, eUp->Org, orgUp, dstUp, orgLo, dstLo );
+ RegionAbove(regUp)->dirty = regUp->dirty = regLo->dirty = TRUE;
+ return FALSE;
+}
+
+static void WalkDirtyRegions( GLUtesselator *tess, ActiveRegion *regUp )
+/*
+ * When the upper or lower edge of any region changes, the region is
+ * marked "dirty". This routine walks through all the dirty regions
+ * and makes sure that the dictionary invariants are satisfied
+ * (see the comments at the beginning of this file). Of course
+ * new dirty regions can be created as we make changes to restore
+ * the invariants.
+ */
+{
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp, *eLo;
+
+ for( ;; ) {
+ /* Find the lowest dirty region (we walk from the bottom up). */
+ while( regLo->dirty ) {
+ regUp = regLo;
+ regLo = RegionBelow(regLo);
+ }
+ if( ! regUp->dirty ) {
+ regLo = regUp;
+ regUp = RegionAbove( regUp );
+ if( regUp == NULL || ! regUp->dirty ) {
+ /* We've walked all the dirty regions */
+ return;
+ }
+ }
+ regUp->dirty = FALSE;
+ eUp = regUp->eUp;
+ eLo = regLo->eUp;
+
+ if( eUp->Dst != eLo->Dst ) {
+ /* Check that the edge ordering is obeyed at the Dst vertices. */
+ if( CheckForLeftSplice( tess, regUp )) {
+
+ /* If the upper or lower edge was marked fixUpperEdge, then
+ * we no longer need it (since these edges are needed only for
+ * vertices which otherwise have no right-going edges).
+ */
+ if( regLo->fixUpperEdge ) {
+ DeleteRegion( tess, regLo );
+ if ( !__gl_meshDelete( eLo ) ) longjmp(tess->env,1);
+ regLo = RegionBelow( regUp );
+ eLo = regLo->eUp;
+ } else if( regUp->fixUpperEdge ) {
+ DeleteRegion( tess, regUp );
+ if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+ regUp = RegionAbove( regLo );
+ eUp = regUp->eUp;
+ }
+ }
+ }
+ if( eUp->Org != eLo->Org ) {
+ if( eUp->Dst != eLo->Dst
+ && ! regUp->fixUpperEdge && ! regLo->fixUpperEdge
+ && (eUp->Dst == tess->event || eLo->Dst == tess->event) )
+ {
+ /* When all else fails in CheckForIntersect(), it uses tess->event
+ * as the intersection location. To make this possible, it requires
+ * that tess->event lie between the upper and lower edges, and also
+ * that neither of these is marked fixUpperEdge (since in the worst
+ * case it might splice one of these edges into tess->event, and
+ * violate the invariant that fixable edges are the only right-going
+ * edge from their associated vertex).
+ */
+ if( CheckForIntersect( tess, regUp )) {
+ /* WalkDirtyRegions() was called recursively; we're done */
+ return;
+ }
+ } else {
+ /* Even though we can't use CheckForIntersect(), the Org vertices
+ * may violate the dictionary edge ordering. Check and correct this.
+ */
+ (void) CheckForRightSplice( tess, regUp );
+ }
+ }
+ if( eUp->Org == eLo->Org && eUp->Dst == eLo->Dst ) {
+ /* A degenerate loop consisting of only two edges -- delete it. */
+ AddWinding( eLo, eUp );
+ DeleteRegion( tess, regUp );
+ if ( !__gl_meshDelete( eUp ) ) longjmp(tess->env,1);
+ regUp = RegionAbove( regLo );
+ }
+ }
+}
+
+
+static void ConnectRightVertex( GLUtesselator *tess, ActiveRegion *regUp,
+ GLUhalfEdge *eBottomLeft )
+/*
+ * Purpose: connect a "right" vertex vEvent (one where all edges go left)
+ * to the unprocessed portion of the mesh. Since there are no right-going
+ * edges, two regions (one above vEvent and one below) are being merged
+ * into one. "regUp" is the upper of these two regions.
+ *
+ * There are two reasons for doing this (adding a right-going edge):
+ * - if the two regions being merged are "inside", we must add an edge
+ * to keep them separated (the combined region would not be monotone).
+ * - in any case, we must leave some record of vEvent in the dictionary,
+ * so that we can merge vEvent with features that we have not seen yet.
+ * For example, maybe there is a vertical edge which passes just to
+ * the right of vEvent; we would like to splice vEvent into this edge.
+ *
+ * However, we don't want to connect vEvent to just any vertex. We don''t
+ * want the new edge to cross any other edges; otherwise we will create
+ * intersection vertices even when the input data had no self-intersections.
+ * (This is a bad thing; if the user's input data has no intersections,
+ * we don't want to generate any false intersections ourselves.)
+ *
+ * Our eventual goal is to connect vEvent to the leftmost unprocessed
+ * vertex of the combined region (the union of regUp and regLo).
+ * But because of unseen vertices with all right-going edges, and also
+ * new vertices which may be created by edge intersections, we don''t
+ * know where that leftmost unprocessed vertex is. In the meantime, we
+ * connect vEvent to the closest vertex of either chain, and mark the region
+ * as "fixUpperEdge". This flag says to delete and reconnect this edge
+ * to the next processed vertex on the boundary of the combined region.
+ * Quite possibly the vertex we connected to will turn out to be the
+ * closest one, in which case we won''t need to make any changes.
+ */
+{
+ GLUhalfEdge *eNew;
+ GLUhalfEdge *eTopLeft = eBottomLeft->Onext;
+ ActiveRegion *regLo = RegionBelow(regUp);
+ GLUhalfEdge *eUp = regUp->eUp;
+ GLUhalfEdge *eLo = regLo->eUp;
+ int degenerate = FALSE;
+
+ if( eUp->Dst != eLo->Dst ) {
+ (void) CheckForIntersect( tess, regUp );
+ }
+
+ /* Possible new degeneracies: upper or lower edge of regUp may pass
+ * through vEvent, or may coincide with new intersection vertex
+ */
+ if( VertEq( eUp->Org, tess->event )) {
+ if ( !__gl_meshSplice( eTopLeft->Oprev, eUp ) ) longjmp(tess->env,1);
+ regUp = TopLeftRegion( regUp );
+ if (regUp == NULL) longjmp(tess->env,1);
+ eTopLeft = RegionBelow( regUp )->eUp;
+ FinishLeftRegions( tess, RegionBelow(regUp), regLo );
+ degenerate = TRUE;
+ }
+ if( VertEq( eLo->Org, tess->event )) {
+ if ( !__gl_meshSplice( eBottomLeft, eLo->Oprev ) ) longjmp(tess->env,1);
+ eBottomLeft = FinishLeftRegions( tess, regLo, NULL );
+ degenerate = TRUE;
+ }
+ if( degenerate ) {
+ AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+ return;
+ }
+
+ /* Non-degenerate situation -- need to add a temporary, fixable edge.
+ * Connect to the closer of eLo->Org, eUp->Org.
+ */
+ if( VertLeq( eLo->Org, eUp->Org )) {
+ eNew = eLo->Oprev;
+ } else {
+ eNew = eUp;
+ }
+ eNew = __gl_meshConnect( eBottomLeft->Lprev, eNew );
+ if (eNew == NULL) longjmp(tess->env,1);
+
+ /* Prevent cleanup, otherwise eNew might disappear before we've even
+ * had a chance to mark it as a temporary edge.
+ */
+ AddRightEdges( tess, regUp, eNew, eNew->Onext, eNew->Onext, FALSE );
+ eNew->Sym->activeRegion->fixUpperEdge = TRUE;
+ WalkDirtyRegions( tess, regUp );
+}
+
+/* Because vertices at exactly the same location are merged together
+ * before we process the sweep event, some degenerate cases can't occur.
+ * However if someone eventually makes the modifications required to
+ * merge features which are close together, the cases below marked
+ * TOLERANCE_NONZERO will be useful. They were debugged before the
+ * code to merge identical vertices in the main loop was added.
+ */
+#define TOLERANCE_NONZERO FALSE
+
+static void ConnectLeftDegenerate( GLUtesselator *tess,
+ ActiveRegion *regUp, GLUvertex *vEvent )
+/*
+ * The event vertex lies exacty on an already-processed edge or vertex.
+ * Adding the new vertex involves splicing it into the already-processed
+ * part of the mesh.
+ */
+{
+ GLUhalfEdge *e, *eTopLeft, *eTopRight, *eLast;
+ ActiveRegion *reg;
+
+ e = regUp->eUp;
+ if( VertEq( e->Org, vEvent )) {
+ /* e->Org is an unprocessed vertex - just combine them, and wait
+ * for e->Org to be pulled from the queue
+ */
+ assert( TOLERANCE_NONZERO );
+ SpliceMergeVertices( tess, e, vEvent->anEdge );
+ return;
+ }
+
+ if( ! VertEq( e->Dst, vEvent )) {
+ /* General case -- splice vEvent into edge e which passes through it */
+ if (__gl_meshSplitEdge( e->Sym ) == NULL) longjmp(tess->env,1);
+ if( regUp->fixUpperEdge ) {
+ /* This edge was fixable -- delete unused portion of original edge */
+ if ( !__gl_meshDelete( e->Onext ) ) longjmp(tess->env,1);
+ regUp->fixUpperEdge = FALSE;
+ }
+ if ( !__gl_meshSplice( vEvent->anEdge, e ) ) longjmp(tess->env,1);
+ SweepEvent( tess, vEvent ); /* recurse */
+ return;
+ }
+
+ /* vEvent coincides with e->Dst, which has already been processed.
+ * Splice in the additional right-going edges.
+ */
+ assert( TOLERANCE_NONZERO );
+ regUp = TopRightRegion( regUp );
+ reg = RegionBelow( regUp );
+ eTopRight = reg->eUp->Sym;
+ eTopLeft = eLast = eTopRight->Onext;
+ if( reg->fixUpperEdge ) {
+ /* Here e->Dst has only a single fixable edge going right.
+ * We can delete it since now we have some real right-going edges.
+ */
+ assert( eTopLeft != eTopRight ); /* there are some left edges too */
+ DeleteRegion( tess, reg );
+ if ( !__gl_meshDelete( eTopRight ) ) longjmp(tess->env,1);
+ eTopRight = eTopLeft->Oprev;
+ }
+ if ( !__gl_meshSplice( vEvent->anEdge, eTopRight ) ) longjmp(tess->env,1);
+ if( ! EdgeGoesLeft( eTopLeft )) {
+ /* e->Dst had no left-going edges -- indicate this to AddRightEdges() */
+ eTopLeft = NULL;
+ }
+ AddRightEdges( tess, regUp, eTopRight->Onext, eLast, eTopLeft, TRUE );
+}
+
+
+static void ConnectLeftVertex( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Purpose: connect a "left" vertex (one where both edges go right)
+ * to the processed portion of the mesh. Let R be the active region
+ * containing vEvent, and let U and L be the upper and lower edge
+ * chains of R. There are two possibilities:
+ *
+ * - the normal case: split R into two regions, by connecting vEvent to
+ * the rightmost vertex of U or L lying to the left of the sweep line
+ *
+ * - the degenerate case: if vEvent is close enough to U or L, we
+ * merge vEvent into that edge chain. The subcases are:
+ * - merging with the rightmost vertex of U or L
+ * - merging with the active edge of U or L
+ * - merging with an already-processed portion of U or L
+ */
+{
+ ActiveRegion *regUp, *regLo, *reg;
+ GLUhalfEdge *eUp, *eLo, *eNew;
+ ActiveRegion tmp;
+
+ /* assert( vEvent->anEdge->Onext->Onext == vEvent->anEdge ); */
+
+ /* Get a pointer to the active region containing vEvent */
+ tmp.eUp = vEvent->anEdge->Sym;
+ /* __GL_DICTLISTKEY */ /* __gl_dictListSearch */
+ regUp = (ActiveRegion *)dictKey( dictSearch( tess->dict, &tmp ));
+ regLo = RegionBelow( regUp );
+ eUp = regUp->eUp;
+ eLo = regLo->eUp;
+
+ /* Try merging with U or L first */
+ if( EdgeSign( eUp->Dst, vEvent, eUp->Org ) == 0 ) {
+ ConnectLeftDegenerate( tess, regUp, vEvent );
+ return;
+ }
+
+ /* Connect vEvent to rightmost processed vertex of either chain.
+ * e->Dst is the vertex that we will connect to vEvent.
+ */
+ reg = VertLeq( eLo->Dst, eUp->Dst ) ? regUp : regLo;
+
+ if( regUp->inside || reg->fixUpperEdge) {
+ if( reg == regUp ) {
+ eNew = __gl_meshConnect( vEvent->anEdge->Sym, eUp->Lnext );
+ if (eNew == NULL) longjmp(tess->env,1);
+ } else {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( eLo->Dnext, vEvent->anEdge);
+ if (tempHalfEdge == NULL) longjmp(tess->env,1);
+
+ eNew = tempHalfEdge->Sym;
+ }
+ if( reg->fixUpperEdge ) {
+ if ( !FixUpperEdge( reg, eNew ) ) longjmp(tess->env,1);
+ } else {
+ ComputeWinding( tess, AddRegionBelow( tess, regUp, eNew ));
+ }
+ SweepEvent( tess, vEvent );
+ } else {
+ /* The new vertex is in a region which does not belong to the polygon.
+ * We don''t need to connect this vertex to the rest of the mesh.
+ */
+ AddRightEdges( tess, regUp, vEvent->anEdge, vEvent->anEdge, NULL, TRUE );
+ }
+}
+
+
+static void SweepEvent( GLUtesselator *tess, GLUvertex *vEvent )
+/*
+ * Does everything necessary when the sweep line crosses a vertex.
+ * Updates the mesh and the edge dictionary.
+ */
+{
+ ActiveRegion *regUp, *reg;
+ GLUhalfEdge *e, *eTopLeft, *eBottomLeft;
+
+ tess->event = vEvent; /* for access in EdgeLeq() */
+ DebugEvent( tess );
+
+ /* Check if this vertex is the right endpoint of an edge that is
+ * already in the dictionary. In this case we don't need to waste
+ * time searching for the location to insert new edges.
+ */
+ e = vEvent->anEdge;
+ while( e->activeRegion == NULL ) {
+ e = e->Onext;
+ if( e == vEvent->anEdge ) {
+ /* All edges go right -- not incident to any processed edges */
+ ConnectLeftVertex( tess, vEvent );
+ return;
+ }
+ }
+
+ /* Processing consists of two phases: first we "finish" all the
+ * active regions where both the upper and lower edges terminate
+ * at vEvent (ie. vEvent is closing off these regions).
+ * We mark these faces "inside" or "outside" the polygon according
+ * to their winding number, and delete the edges from the dictionary.
+ * This takes care of all the left-going edges from vEvent.
+ */
+ regUp = TopLeftRegion( e->activeRegion );
+ if (regUp == NULL) longjmp(tess->env,1);
+ reg = RegionBelow( regUp );
+ eTopLeft = reg->eUp;
+ eBottomLeft = FinishLeftRegions( tess, reg, NULL );
+
+ /* Next we process all the right-going edges from vEvent. This
+ * involves adding the edges to the dictionary, and creating the
+ * associated "active regions" which record information about the
+ * regions between adjacent dictionary edges.
+ */
+ if( eBottomLeft->Onext == eTopLeft ) {
+ /* No right-going edges -- add a temporary "fixable" edge */
+ ConnectRightVertex( tess, regUp, eBottomLeft );
+ } else {
+ AddRightEdges( tess, regUp, eBottomLeft->Onext, eTopLeft, eTopLeft, TRUE );
+ }
+}
+
+
+/* Make the sentinel coordinates big enough that they will never be
+ * merged with real input features. (Even with the largest possible
+ * input contour and the maximum tolerance of 1.0, no merging will be
+ * done with coordinates larger than 3 * GLU_TESS_MAX_COORD).
+ */
+#define SENTINEL_COORD (4 * GLU_TESS_MAX_COORD)
+
+static void AddSentinel( GLUtesselator *tess, GLdouble t )
+/*
+ * We add two sentinel edges above and below all other edges,
+ * to avoid special cases at the top and bottom.
+ */
+{
+ GLUhalfEdge *e;
+ ActiveRegion *reg = (ActiveRegion *)memAlloc( sizeof( ActiveRegion ));
+ if (reg == NULL) longjmp(tess->env,1);
+
+ e = __gl_meshMakeEdge( tess->mesh );
+ if (e == NULL) longjmp(tess->env,1);
+
+ e->Org->s = SENTINEL_COORD;
+ e->Org->t = t;
+ e->Dst->s = -SENTINEL_COORD;
+ e->Dst->t = t;
+ tess->event = e->Dst; /* initialize it */
+
+ reg->eUp = e;
+ reg->windingNumber = 0;
+ reg->inside = FALSE;
+ reg->fixUpperEdge = FALSE;
+ reg->sentinel = TRUE;
+ reg->dirty = FALSE;
+ reg->nodeUp = dictInsert( tess->dict, reg ); /* __gl_dictListInsertBefore */
+ if (reg->nodeUp == NULL) longjmp(tess->env,1);
+}
+
+
+static void InitEdgeDict( GLUtesselator *tess )
+/*
+ * We maintain an ordering of edge intersections with the sweep line.
+ * This order is maintained in a dynamic dictionary.
+ */
+{
+ /* __gl_dictListNewDict */
+ tess->dict = dictNewDict( tess, (int (*)(void *, DictKey, DictKey)) EdgeLeq );
+ if (tess->dict == NULL) longjmp(tess->env,1);
+
+ AddSentinel( tess, -SENTINEL_COORD );
+ AddSentinel( tess, SENTINEL_COORD );
+}
+
+
+static void DoneEdgeDict( GLUtesselator *tess )
+{
+ ActiveRegion *reg;
+#ifndef NDEBUG
+ int fixedEdges = 0;
+#endif
+
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ while( (reg = (ActiveRegion *)dictKey( dictMin( tess->dict ))) != NULL ) {
+ /*
+ * At the end of all processing, the dictionary should contain
+ * only the two sentinel edges, plus at most one "fixable" edge
+ * created by ConnectRightVertex().
+ */
+ if( ! reg->sentinel ) {
+ assert( reg->fixUpperEdge );
+ assert( ++fixedEdges == 1 );
+ }
+ assert( reg->windingNumber == 0 );
+ DeleteRegion( tess, reg );
+/* __gl_meshDelete( reg->eUp );*/
+ }
+ dictDeleteDict( tess->dict ); /* __gl_dictListDeleteDict */
+}
+
+
+static void RemoveDegenerateEdges( GLUtesselator *tess )
+/*
+ * Remove zero-length edges, and contours with fewer than 3 vertices.
+ */
+{
+ GLUhalfEdge *e, *eNext, *eLnext;
+ GLUhalfEdge *eHead = &tess->mesh->eHead;
+
+ /*LINTED*/
+ for( e = eHead->next; e != eHead; e = eNext ) {
+ eNext = e->next;
+ eLnext = e->Lnext;
+
+ if( VertEq( e->Org, e->Dst ) && e->Lnext->Lnext != e ) {
+ /* Zero-length edge, contour has at least 3 edges */
+
+ SpliceMergeVertices( tess, eLnext, e ); /* deletes e->Org */
+ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1); /* e is a self-loop */
+ e = eLnext;
+ eLnext = e->Lnext;
+ }
+ if( eLnext->Lnext == e ) {
+ /* Degenerate contour (one or two edges) */
+
+ if( eLnext != e ) {
+ if( eLnext == eNext || eLnext == eNext->Sym ) { eNext = eNext->next; }
+ if ( !__gl_meshDelete( eLnext ) ) longjmp(tess->env,1);
+ }
+ if( e == eNext || e == eNext->Sym ) { eNext = eNext->next; }
+ if ( !__gl_meshDelete( e ) ) longjmp(tess->env,1);
+ }
+ }
+}
+
+static int InitPriorityQ( GLUtesselator *tess )
+/*
+ * Insert all vertices into the priority queue which determines the
+ * order in which vertices cross the sweep line.
+ */
+{
+ PriorityQ *pq;
+ GLUvertex *v, *vHead;
+
+ /* __gl_pqSortNewPriorityQ */
+ pq = tess->pq = pqNewPriorityQ( (int (*)(PQkey, PQkey)) __gl_vertLeq );
+ if (pq == NULL) return 0;
+
+ vHead = &tess->mesh->vHead;
+ for( v = vHead->next; v != vHead; v = v->next ) {
+ v->pqHandle = pqInsert( pq, v ); /* __gl_pqSortInsert */
+ if (v->pqHandle == LONG_MAX) break;
+ }
+ if (v != vHead || !pqInit( pq ) ) { /* __gl_pqSortInit */
+ pqDeletePriorityQ(tess->pq); /* __gl_pqSortDeletePriorityQ */
+ tess->pq = NULL;
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static void DonePriorityQ( GLUtesselator *tess )
+{
+ pqDeletePriorityQ( tess->pq ); /* __gl_pqSortDeletePriorityQ */
+}
+
+
+static int RemoveDegenerateFaces( GLUmesh *mesh )
+/*
+ * Delete any degenerate faces with only two edges. WalkDirtyRegions()
+ * will catch almost all of these, but it won't catch degenerate faces
+ * produced by splice operations on already-processed edges.
+ * The two places this can happen are in FinishLeftRegions(), when
+ * we splice in a "temporary" edge produced by ConnectRightVertex(),
+ * and in CheckForLeftSplice(), where we splice already-processed
+ * edges to ensure that our dictionary invariants are not violated
+ * by numerical errors.
+ *
+ * In both these cases it is *very* dangerous to delete the offending
+ * edge at the time, since one of the routines further up the stack
+ * will sometimes be keeping a pointer to that edge.
+ */
+{
+ GLUface *f, *fNext;
+ GLUhalfEdge *e;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = fNext ) {
+ fNext = f->next;
+ e = f->anEdge;
+ assert( e->Lnext != e );
+
+ if( e->Lnext->Lnext == e ) {
+ /* A face with only two edges */
+ AddWinding( e->Onext, e );
+ if ( !__gl_meshDelete( e ) ) return 0;
+ }
+ }
+ return 1;
+}
+
+int __gl_computeInterior( GLUtesselator *tess )
+/*
+ * __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+{
+ GLUvertex *v, *vNext;
+
+ tess->fatalError = FALSE;
+
+ /* Each vertex defines an event for our sweep line. Start by inserting
+ * all the vertices in a priority queue. Events are processed in
+ * lexicographic order, ie.
+ *
+ * e1 < e2 iff e1.x < e2.x || (e1.x == e2.x && e1.y < e2.y)
+ */
+ RemoveDegenerateEdges( tess );
+ if ( !InitPriorityQ( tess ) ) return 0; /* if error */
+ InitEdgeDict( tess );
+
+ /* __gl_pqSortExtractMin */
+ while( (v = (GLUvertex *)pqExtractMin( tess->pq )) != NULL ) {
+ for( ;; ) {
+ vNext = (GLUvertex *)pqMinimum( tess->pq ); /* __gl_pqSortMinimum */
+ if( vNext == NULL || ! VertEq( vNext, v )) break;
+
+ /* Merge together all vertices at exactly the same location.
+ * This is more efficient than processing them one at a time,
+ * simplifies the code (see ConnectLeftDegenerate), and is also
+ * important for correct handling of certain degenerate cases.
+ * For example, suppose there are two identical edges A and B
+ * that belong to different contours (so without this code they would
+ * be processed by separate sweep events). Suppose another edge C
+ * crosses A and B from above. When A is processed, we split it
+ * at its intersection point with C. However this also splits C,
+ * so when we insert B we may compute a slightly different
+ * intersection point. This might leave two edges with a small
+ * gap between them. This kind of error is especially obvious
+ * when using boundary extraction (GLU_TESS_BOUNDARY_ONLY).
+ */
+ vNext = (GLUvertex *)pqExtractMin( tess->pq ); /* __gl_pqSortExtractMin*/
+ SpliceMergeVertices( tess, v->anEdge, vNext->anEdge );
+ }
+ SweepEvent( tess, v );
+ }
+
+ /* Set tess->event for debugging purposes */
+ /* __GL_DICTLISTKEY */ /* __GL_DICTLISTMIN */
+ tess->event = ((ActiveRegion *) dictKey( dictMin( tess->dict )))->eUp->Org;
+ DebugEvent( tess );
+ DoneEdgeDict( tess );
+ DonePriorityQ( tess );
+
+ if ( !RemoveDegenerateFaces( tess->mesh ) ) return 0;
+ __gl_meshCheckMesh( tess->mesh );
+
+ return 1;
+}
diff --git a/Source/ThirdParty/glu/libtess/sweep.h b/Source/ThirdParty/glu/libtess/sweep.h
new file mode 100644
index 000000000..75d3e6409
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/sweep.h
@@ -0,0 +1,84 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/sweep.h#5 $
+*/
+
+#ifndef __sweep_h_
+#define __sweep_h_
+
+#include "mesh.h"
+
+/* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+int __gl_computeInterior( GLUtesselator *tess );
+
+
+/* The following is here *only* for access by debugging routines */
+
+#include "dict.h"
+
+/* For each pair of adjacent edges crossing the sweep line, there is
+ * an ActiveRegion to represent the region between them. The active
+ * regions are kept in sorted order in a dynamic dictionary. As the
+ * sweep line crosses each vertex, we update the affected regions.
+ */
+
+struct ActiveRegion {
+ GLUhalfEdge *eUp; /* upper edge, directed right to left */
+ DictNode *nodeUp; /* dictionary node corresponding to eUp */
+ int windingNumber; /* used to determine which regions are
+ * inside the polygon */
+ GLboolean inside; /* is this region inside the polygon? */
+ GLboolean sentinel; /* marks fake edges at t = +/-infinity */
+ GLboolean dirty; /* marks regions where the upper or lower
+ * edge has changed, but we haven't checked
+ * whether they intersect yet */
+ GLboolean fixUpperEdge; /* marks temporary edges introduced when
+ * we process a "right vertex" (one without
+ * any edges leaving to the right) */
+};
+
+#define RegionBelow(r) ((ActiveRegion *) dictKey(dictPred((r)->nodeUp)))
+#define RegionAbove(r) ((ActiveRegion *) dictKey(dictSucc((r)->nodeUp)))
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/tess.c b/Source/ThirdParty/glu/libtess/tess.c
new file mode 100644
index 000000000..c59a17896
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/tess.c
@@ -0,0 +1,638 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/tess.c#7 $
+*/
+
+#include "gluos.h"
+#include <stddef.h>
+#include <assert.h>
+#include <setjmp.h>
+#include "memalloc.h"
+#include "tess.h"
+#include "mesh.h"
+#include "normal.h"
+#include "sweep.h"
+#include "tessmono.h"
+#include "render.h"
+
+#define GLU_TESS_DEFAULT_TOLERANCE 0.0
+#define GLU_TESS_MESH 100112 /* void (*)(GLUmesh *mesh) */
+
+#define TRUE 1
+#define FALSE 0
+
+/*ARGSUSED*/ static void GLAPIENTRY noBegin( GLenum type ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEdgeFlag( GLboolean boundaryEdge ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noVertex( void *data ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noEnd( void ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noError( GLenum errnum ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noCombine( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **dataOut ) {}
+/*ARGSUSED*/ static void GLAPIENTRY noMesh( GLUmesh *mesh ) {}
+
+
+/*ARGSUSED*/ void GLAPIENTRY __gl_noBeginData( GLenum type,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noVertexData( void *data,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noEndData( void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noErrorData( GLenum errnum,
+ void *polygonData ) {}
+/*ARGSUSED*/ void GLAPIENTRY __gl_noCombineData( GLdouble coords[3],
+ void *data[4],
+ GLfloat weight[4],
+ void **outData,
+ void *polygonData ) {}
+
+/* Half-edges are allocated in pairs (see mesh.c) */
+typedef struct { GLUhalfEdge e, eSym; } EdgePair;
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define MAX_FAST_ALLOC (MAX(sizeof(EdgePair), \
+ MAX(sizeof(GLUvertex),sizeof(GLUface))))
+
+
+GLUtesselator * GLAPIENTRY
+gluNewTess( void )
+{
+ GLUtesselator *tess;
+
+ /* Only initialize fields which can be changed by the api. Other fields
+ * are initialized where they are used.
+ */
+
+ if (memInit( MAX_FAST_ALLOC ) == 0) {
+ return 0; /* out of memory */
+ }
+ tess = (GLUtesselator *)memAlloc( sizeof( GLUtesselator ));
+ if (tess == NULL) {
+ return 0; /* out of memory */
+ }
+
+ tess->state = T_DORMANT;
+
+ tess->normal[0] = 0;
+ tess->normal[1] = 0;
+ tess->normal[2] = 0;
+
+ tess->relTolerance = GLU_TESS_DEFAULT_TOLERANCE;
+ tess->windingRule = GLU_TESS_WINDING_ODD;
+ tess->flagBoundary = FALSE;
+ tess->boundaryOnly = FALSE;
+
+ tess->callBegin = &noBegin;
+ tess->callEdgeFlag = &noEdgeFlag;
+ tess->callVertex = &noVertex;
+ tess->callEnd = &noEnd;
+
+ tess->callError = &noError;
+ tess->callCombine = &noCombine;
+ tess->callMesh = &noMesh;
+
+ tess->callBeginData= &__gl_noBeginData;
+ tess->callEdgeFlagData= &__gl_noEdgeFlagData;
+ tess->callVertexData= &__gl_noVertexData;
+ tess->callEndData= &__gl_noEndData;
+ tess->callErrorData= &__gl_noErrorData;
+ tess->callCombineData= &__gl_noCombineData;
+
+ tess->polygonData= NULL;
+
+ return tess;
+}
+
+static void MakeDormant( GLUtesselator *tess )
+{
+ /* Return the tessellator to its original dormant state. */
+
+ if( tess->mesh != NULL ) {
+ __gl_meshDeleteMesh( tess->mesh );
+ }
+ tess->state = T_DORMANT;
+ tess->lastEdge = NULL;
+ tess->mesh = NULL;
+}
+
+#define RequireState( tess, s ) if( tess->state != s ) GotoState(tess,s)
+
+static void GotoState( GLUtesselator *tess, enum TessState newState )
+{
+ while( tess->state != newState ) {
+ /* We change the current state one level at a time, to get to
+ * the desired state.
+ */
+ if( tess->state < newState ) {
+ switch( tess->state ) {
+ case T_DORMANT:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_POLYGON );
+ gluTessBeginPolygon( tess, NULL );
+ break;
+ case T_IN_POLYGON:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_BEGIN_CONTOUR );
+ gluTessBeginContour( tess );
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ } else {
+ switch( tess->state ) {
+ case T_IN_CONTOUR:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_CONTOUR );
+ gluTessEndContour( tess );
+ break;
+ case T_IN_POLYGON:
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_MISSING_END_POLYGON );
+ /* gluTessEndPolygon( tess ) is too much work! */
+ MakeDormant( tess );
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ }
+}
+
+
+void GLAPIENTRY
+gluDeleteTess( GLUtesselator *tess )
+{
+ RequireState( tess, T_DORMANT );
+ memFree( tess );
+}
+
+
+void GLAPIENTRY
+gluTessProperty( GLUtesselator *tess, GLenum which, GLdouble value )
+{
+ GLenum windingRule;
+
+ switch( which ) {
+ case GLU_TESS_TOLERANCE:
+ if( value < 0.0 || value > 1.0 ) break;
+ tess->relTolerance = value;
+ return;
+
+ case GLU_TESS_WINDING_RULE:
+ windingRule = (GLenum) value;
+ if( windingRule != value ) break; /* not an integer */
+
+ switch( windingRule ) {
+ case GLU_TESS_WINDING_ODD:
+ case GLU_TESS_WINDING_NONZERO:
+ case GLU_TESS_WINDING_POSITIVE:
+ case GLU_TESS_WINDING_NEGATIVE:
+ case GLU_TESS_WINDING_ABS_GEQ_TWO:
+ tess->windingRule = windingRule;
+ return;
+ default:
+ break;
+ }
+
+ case GLU_TESS_BOUNDARY_ONLY:
+ tess->boundaryOnly = (value != 0);
+ return;
+
+ default:
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ return;
+ }
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_VALUE );
+}
+
+/* Returns tessellator property */
+void GLAPIENTRY
+gluGetTessProperty( GLUtesselator *tess, GLenum which, GLdouble *value )
+{
+ switch (which) {
+ case GLU_TESS_TOLERANCE:
+ /* tolerance should be in range [0..1] */
+ assert(0.0 <= tess->relTolerance && tess->relTolerance <= 1.0);
+ *value= tess->relTolerance;
+ break;
+ case GLU_TESS_WINDING_RULE:
+ assert(tess->windingRule == GLU_TESS_WINDING_ODD ||
+ tess->windingRule == GLU_TESS_WINDING_NONZERO ||
+ tess->windingRule == GLU_TESS_WINDING_POSITIVE ||
+ tess->windingRule == GLU_TESS_WINDING_NEGATIVE ||
+ tess->windingRule == GLU_TESS_WINDING_ABS_GEQ_TWO);
+ *value= tess->windingRule;
+ break;
+ case GLU_TESS_BOUNDARY_ONLY:
+ assert(tess->boundaryOnly == TRUE || tess->boundaryOnly == FALSE);
+ *value= tess->boundaryOnly;
+ break;
+ default:
+ *value= 0.0;
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ break;
+ }
+} /* gluGetTessProperty() */
+
+void GLAPIENTRY
+gluTessNormal( GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z )
+{
+ tess->normal[0] = x;
+ tess->normal[1] = y;
+ tess->normal[2] = z;
+}
+
+void GLAPIENTRY
+gluTessCallback( GLUtesselator *tess, GLenum which, void (GLAPIENTRY *fn)())
+{
+ switch( which ) {
+ case GLU_TESS_BEGIN:
+ tess->callBegin = (fn == NULL) ? &noBegin : (void (GLAPIENTRY *)(GLenum)) fn;
+ return;
+ case GLU_TESS_BEGIN_DATA:
+ tess->callBeginData = (fn == NULL) ?
+ &__gl_noBeginData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+ return;
+ case GLU_TESS_EDGE_FLAG:
+ tess->callEdgeFlag = (fn == NULL) ? &noEdgeFlag :
+ (void (GLAPIENTRY *)(GLboolean)) fn;
+ /* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ tess->flagBoundary = (fn != NULL);
+ return;
+ case GLU_TESS_EDGE_FLAG_DATA:
+ tess->callEdgeFlagData= (fn == NULL) ?
+ &__gl_noEdgeFlagData : (void (GLAPIENTRY *)(GLboolean, void *)) fn;
+ /* If the client wants boundary edges to be flagged,
+ * we render everything as separate triangles (no strips or fans).
+ */
+ tess->flagBoundary = (fn != NULL);
+ return;
+ case GLU_TESS_VERTEX:
+ tess->callVertex = (fn == NULL) ? &noVertex :
+ (void (GLAPIENTRY *)(void *)) fn;
+ return;
+ case GLU_TESS_VERTEX_DATA:
+ tess->callVertexData = (fn == NULL) ?
+ &__gl_noVertexData : (void (GLAPIENTRY *)(void *, void *)) fn;
+ return;
+ case GLU_TESS_END:
+ tess->callEnd = (fn == NULL) ? &noEnd : (void (GLAPIENTRY *)(void)) fn;
+ return;
+ case GLU_TESS_END_DATA:
+ tess->callEndData = (fn == NULL) ? &__gl_noEndData :
+ (void (GLAPIENTRY *)(void *)) fn;
+ return;
+ case GLU_TESS_ERROR:
+ tess->callError = (fn == NULL) ? &noError : (void (GLAPIENTRY *)(GLenum)) fn;
+ return;
+ case GLU_TESS_ERROR_DATA:
+ tess->callErrorData = (fn == NULL) ?
+ &__gl_noErrorData : (void (GLAPIENTRY *)(GLenum, void *)) fn;
+ return;
+ case GLU_TESS_COMBINE:
+ tess->callCombine = (fn == NULL) ? &noCombine :
+ (void (GLAPIENTRY *)(GLdouble [3],void *[4], GLfloat [4], void ** )) fn;
+ return;
+ case GLU_TESS_COMBINE_DATA:
+ tess->callCombineData = (fn == NULL) ? &__gl_noCombineData :
+ (void (GLAPIENTRY *)(GLdouble [3],
+ void *[4],
+ GLfloat [4],
+ void **,
+ void *)) fn;
+ return;
+ case GLU_TESS_MESH:
+ tess->callMesh = (fn == NULL) ? &noMesh : (void (GLAPIENTRY *)(GLUmesh *)) fn;
+ return;
+ default:
+ CALL_ERROR_OR_ERROR_DATA( GLU_INVALID_ENUM );
+ return;
+ }
+}
+
+static int AddVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ GLUhalfEdge *e;
+
+ e = tess->lastEdge;
+ if( e == NULL ) {
+ /* Make a self-loop (one vertex, one edge). */
+
+ e = __gl_meshMakeEdge( tess->mesh );
+ if (e == NULL) return 0;
+ if ( !__gl_meshSplice( e, e->Sym ) ) return 0;
+ } else {
+ /* Create a new vertex and edge which immediately follow e
+ * in the ordering around the left face.
+ */
+ if (__gl_meshSplitEdge( e ) == NULL) return 0;
+ e = e->Lnext;
+ }
+
+ /* The new vertex is now e->Org. */
+ e->Org->data = data;
+ e->Org->coords[0] = coords[0];
+ e->Org->coords[1] = coords[1];
+ e->Org->coords[2] = coords[2];
+
+ /* The winding of an edge says how the winding number changes as we
+ * cross from the edge''s right face to its left face. We add the
+ * vertices in such an order that a CCW contour will add +1 to
+ * the winding number of the region inside the contour.
+ */
+ e->winding = 1;
+ e->Sym->winding = -1;
+
+ tess->lastEdge = e;
+
+ return 1;
+}
+
+
+static void CacheVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ CachedVertex *v = &tess->cache[tess->cacheCount];
+
+ v->data = data;
+ v->coords[0] = coords[0];
+ v->coords[1] = coords[1];
+ v->coords[2] = coords[2];
+ ++tess->cacheCount;
+}
+
+
+static int EmptyCache( GLUtesselator *tess )
+{
+ CachedVertex *v = tess->cache;
+ CachedVertex *vLast;
+
+ tess->mesh = __gl_meshNewMesh();
+ if (tess->mesh == NULL) return 0;
+
+ for( vLast = v + tess->cacheCount; v < vLast; ++v ) {
+ if ( !AddVertex( tess, v->coords, v->data ) ) return 0;
+ }
+ tess->cacheCount = 0;
+ tess->emptyCache = FALSE;
+
+ return 1;
+}
+
+
+void GLAPIENTRY
+gluTessVertex( GLUtesselator *tess, GLdouble coords[3], void *data )
+{
+ int i, tooLarge = FALSE;
+ GLdouble x, clamped[3];
+
+ RequireState( tess, T_IN_CONTOUR );
+
+ if( tess->emptyCache ) {
+ if ( !EmptyCache( tess ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+ tess->lastEdge = NULL;
+ }
+ for( i = 0; i < 3; ++i ) {
+ x = coords[i];
+ if( x < - GLU_TESS_MAX_COORD ) {
+ x = - GLU_TESS_MAX_COORD;
+ tooLarge = TRUE;
+ }
+ if( x > GLU_TESS_MAX_COORD ) {
+ x = GLU_TESS_MAX_COORD;
+ tooLarge = TRUE;
+ }
+ clamped[i] = x;
+ }
+ if( tooLarge ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_TESS_COORD_TOO_LARGE );
+ }
+
+ if( tess->mesh == NULL ) {
+ if( tess->cacheCount < TESS_MAX_CACHE ) {
+ CacheVertex( tess, clamped, data );
+ return;
+ }
+ if ( !EmptyCache( tess ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+ }
+ if ( !AddVertex( tess, clamped, data ) ) {
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ }
+}
+
+
+void GLAPIENTRY
+gluTessBeginPolygon( GLUtesselator *tess, void *data )
+{
+ RequireState( tess, T_DORMANT );
+
+ tess->state = T_IN_POLYGON;
+ tess->cacheCount = 0;
+ tess->emptyCache = FALSE;
+ tess->mesh = NULL;
+
+ tess->polygonData= data;
+}
+
+
+void GLAPIENTRY
+gluTessBeginContour( GLUtesselator *tess )
+{
+ RequireState( tess, T_IN_POLYGON );
+
+ tess->state = T_IN_CONTOUR;
+ tess->lastEdge = NULL;
+ if( tess->cacheCount > 0 ) {
+ /* Just set a flag so we don't get confused by empty contours
+ * -- these can be generated accidentally with the obsolete
+ * NextContour() interface.
+ */
+ tess->emptyCache = TRUE;
+ }
+}
+
+
+void GLAPIENTRY
+gluTessEndContour( GLUtesselator *tess )
+{
+ RequireState( tess, T_IN_CONTOUR );
+ tess->state = T_IN_POLYGON;
+}
+
+void GLAPIENTRY
+gluTessEndPolygon( GLUtesselator *tess )
+{
+ GLUmesh *mesh;
+
+ if (setjmp(tess->env) != 0) {
+ /* come back here if out of memory */
+ CALL_ERROR_OR_ERROR_DATA( GLU_OUT_OF_MEMORY );
+ return;
+ }
+
+ RequireState( tess, T_IN_POLYGON );
+ tess->state = T_DORMANT;
+
+ if( tess->mesh == NULL ) {
+ if( ! tess->flagBoundary && tess->callMesh == &noMesh ) {
+
+ /* Try some special code to make the easy cases go quickly
+ * (eg. convex polygons). This code does NOT handle multiple contours,
+ * intersections, edge flags, and of course it does not generate
+ * an explicit mesh either.
+ */
+ if( __gl_renderCache( tess )) {
+ tess->polygonData= NULL;
+ return;
+ }
+ }
+ if ( !EmptyCache( tess ) ) longjmp(tess->env,1); /* could've used a label*/
+ }
+
+ /* Determine the polygon normal and project vertices onto the plane
+ * of the polygon.
+ */
+ __gl_projectPolygon( tess );
+
+ /* __gl_computeInterior( tess ) computes the planar arrangement specified
+ * by the given contours, and further subdivides this arrangement
+ * into regions. Each region is marked "inside" if it belongs
+ * to the polygon, according to the rule given by tess->windingRule.
+ * Each interior region is guaranteed be monotone.
+ */
+ if ( !__gl_computeInterior( tess ) ) {
+ longjmp(tess->env,1); /* could've used a label */
+ }
+
+ mesh = tess->mesh;
+ if( ! tess->fatalError ) {
+ int rc = 1;
+
+ /* If the user wants only the boundary contours, we throw away all edges
+ * except those which separate the interior from the exterior.
+ * Otherwise we tessellate all the regions marked "inside".
+ */
+ if( tess->boundaryOnly ) {
+ rc = __gl_meshSetWindingNumber( mesh, 1, TRUE );
+ } else {
+ rc = __gl_meshTessellateInterior( mesh );
+ }
+ if (rc == 0) longjmp(tess->env,1); /* could've used a label */
+
+ __gl_meshCheckMesh( mesh );
+
+ if( tess->callBegin != &noBegin || tess->callEnd != &noEnd
+ || tess->callVertex != &noVertex || tess->callEdgeFlag != &noEdgeFlag
+ || tess->callBeginData != &__gl_noBeginData
+ || tess->callEndData != &__gl_noEndData
+ || tess->callVertexData != &__gl_noVertexData
+ || tess->callEdgeFlagData != &__gl_noEdgeFlagData )
+ {
+ if( tess->boundaryOnly ) {
+ __gl_renderBoundary( tess, mesh ); /* output boundary contours */
+ } else {
+ __gl_renderMesh( tess, mesh ); /* output strips and fans */
+ }
+ }
+ if( tess->callMesh != &noMesh ) {
+
+ /* Throw away the exterior faces, so that all faces are interior.
+ * This way the user doesn't have to check the "inside" flag,
+ * and we don't need to even reveal its existence. It also leaves
+ * the freedom for an implementation to not generate the exterior
+ * faces in the first place.
+ */
+ __gl_meshDiscardExterior( mesh );
+ (*tess->callMesh)( mesh ); /* user wants the mesh itself */
+ tess->mesh = NULL;
+ tess->polygonData= NULL;
+ return;
+ }
+ }
+ __gl_meshDeleteMesh( mesh );
+ tess->polygonData= NULL;
+ tess->mesh = NULL;
+}
+
+
+/*XXXblythe unused function*/
+#if 0
+void GLAPIENTRY
+gluDeleteMesh( GLUmesh *mesh )
+{
+ __gl_meshDeleteMesh( mesh );
+}
+#endif
+
+
+
+/*******************************************************/
+
+/* Obsolete calls -- for backward compatibility */
+
+#if 0
+void GLAPIENTRY
+gluBeginPolygon( GLUtesselator *tess )
+{
+ gluTessBeginPolygon( tess, NULL );
+ gluTessBeginContour( tess );
+}
+
+
+/*ARGSUSED*/
+void GLAPIENTRY
+gluNextContour( GLUtesselator *tess, GLenum type )
+{
+ gluTessEndContour( tess );
+ gluTessBeginContour( tess );
+}
+
+
+void GLAPIENTRY
+gluEndPolygon( GLUtesselator *tess )
+{
+ gluTessEndContour( tess );
+ gluTessEndPolygon( tess );
+}
+#endif
diff --git a/Source/ThirdParty/glu/libtess/tess.h b/Source/ThirdParty/glu/libtess/tess.h
new file mode 100644
index 000000000..053fa0098
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/tess.h
@@ -0,0 +1,172 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/tess.h#6 $
+*/
+
+#ifndef __tess_h_
+#define __tess_h_
+
+#include <internal_glu.h>
+#include <setjmp.h>
+#include "mesh.h"
+#include "dict.h"
+#include "priorityq.h"
+
+/* The begin/end calls must be properly nested. We keep track of
+ * the current state to enforce the ordering.
+ */
+enum TessState { T_DORMANT, T_IN_POLYGON, T_IN_CONTOUR };
+
+/* We cache vertex data for single-contour polygons so that we can
+ * try a quick-and-dirty decomposition first.
+ */
+#define TESS_MAX_CACHE 100
+
+typedef struct CachedVertex {
+ GLdouble coords[3];
+ void *data;
+} CachedVertex;
+
+struct GLUtesselator {
+
+ /*** state needed for collecting the input data ***/
+
+ enum TessState state; /* what begin/end calls have we seen? */
+
+ GLUhalfEdge *lastEdge; /* lastEdge->Org is the most recent vertex */
+ GLUmesh *mesh; /* stores the input contours, and eventually
+ the tessellation itself */
+
+ void (GLAPIENTRY *callError)( GLenum errnum );
+
+ /*** state needed for projecting onto the sweep plane ***/
+
+ GLdouble normal[3]; /* user-specified normal (if provided) */
+ GLdouble sUnit[3]; /* unit vector in s-direction (debugging) */
+ GLdouble tUnit[3]; /* unit vector in t-direction (debugging) */
+
+ /*** state needed for the line sweep ***/
+
+ GLdouble relTolerance; /* tolerance for merging features */
+ GLenum windingRule; /* rule for determining polygon interior */
+ GLboolean fatalError; /* fatal error: needed combine callback */
+
+ Dict *dict; /* edge dictionary for sweep line */
+ PriorityQ *pq; /* priority queue of vertex events */
+ GLUvertex *event; /* current sweep event being processed */
+
+ void (GLAPIENTRY *callCombine)( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData );
+
+ /*** state needed for rendering callbacks (see render.c) ***/
+
+ GLboolean flagBoundary; /* mark boundary edges (use EdgeFlag) */
+ GLboolean boundaryOnly; /* Extract contours, not triangles */
+ GLUface *lonelyTriList;
+ /* list of triangles which could not be rendered as strips or fans */
+
+ void (GLAPIENTRY *callBegin)( GLenum type );
+ void (GLAPIENTRY *callEdgeFlag)( GLboolean boundaryEdge );
+ void (GLAPIENTRY *callVertex)( void *data );
+ void (GLAPIENTRY *callEnd)( void );
+ void (GLAPIENTRY *callMesh)( GLUmesh *mesh );
+
+
+ /*** state needed to cache single-contour polygons for renderCache() */
+
+ GLboolean emptyCache; /* empty cache on next vertex() call */
+ int cacheCount; /* number of cached vertices */
+ CachedVertex cache[TESS_MAX_CACHE]; /* the vertex data */
+
+ /*** rendering callbacks that also pass polygon data ***/
+ void (GLAPIENTRY *callBeginData)( GLenum type, void *polygonData );
+ void (GLAPIENTRY *callEdgeFlagData)( GLboolean boundaryEdge,
+ void *polygonData );
+ void (GLAPIENTRY *callVertexData)( void *data, void *polygonData );
+ void (GLAPIENTRY *callEndData)( void *polygonData );
+ void (GLAPIENTRY *callErrorData)( GLenum errnum, void *polygonData );
+ void (GLAPIENTRY *callCombineData)( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData,
+ void *polygonData );
+
+ jmp_buf env; /* place to jump to when memAllocs fail */
+
+ void *polygonData; /* client data for current polygon */
+};
+
+void GLAPIENTRY __gl_noBeginData( GLenum type, void *polygonData );
+void GLAPIENTRY __gl_noEdgeFlagData( GLboolean boundaryEdge, void *polygonData );
+void GLAPIENTRY __gl_noVertexData( void *data, void *polygonData );
+void GLAPIENTRY __gl_noEndData( void *polygonData );
+void GLAPIENTRY __gl_noErrorData( GLenum errnum, void *polygonData );
+void GLAPIENTRY __gl_noCombineData( GLdouble coords[3], void *data[4],
+ GLfloat weight[4], void **outData,
+ void *polygonData );
+
+#define CALL_BEGIN_OR_BEGIN_DATA(a) \
+ if (tess->callBeginData != &__gl_noBeginData) \
+ (*tess->callBeginData)((a),tess->polygonData); \
+ else (*tess->callBegin)((a));
+
+#define CALL_VERTEX_OR_VERTEX_DATA(a) \
+ if (tess->callVertexData != &__gl_noVertexData) \
+ (*tess->callVertexData)((a),tess->polygonData); \
+ else (*tess->callVertex)((a));
+
+#define CALL_EDGE_FLAG_OR_EDGE_FLAG_DATA(a) \
+ if (tess->callEdgeFlagData != &__gl_noEdgeFlagData) \
+ (*tess->callEdgeFlagData)((a),tess->polygonData); \
+ else (*tess->callEdgeFlag)((a));
+
+#define CALL_END_OR_END_DATA() \
+ if (tess->callEndData != &__gl_noEndData) \
+ (*tess->callEndData)(tess->polygonData); \
+ else (*tess->callEnd)();
+
+#define CALL_COMBINE_OR_COMBINE_DATA(a,b,c,d) \
+ if (tess->callCombineData != &__gl_noCombineData) \
+ (*tess->callCombineData)((a),(b),(c),(d),tess->polygonData); \
+ else (*tess->callCombine)((a),(b),(c),(d));
+
+#define CALL_ERROR_OR_ERROR_DATA(a) \
+ if (tess->callErrorData != &__gl_noErrorData) \
+ (*tess->callErrorData)((a),tess->polygonData); \
+ else (*tess->callError)((a));
+
+#endif
diff --git a/Source/ThirdParty/glu/libtess/tessmono.c b/Source/ThirdParty/glu/libtess/tessmono.c
new file mode 100644
index 000000000..2e2cc7901
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/tessmono.c
@@ -0,0 +1,208 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/tessmono.c#5 $
+*/
+
+#include "gluos.h"
+#include <stdlib.h>
+#include "geom.h"
+#include "mesh.h"
+#include "tessmono.h"
+#include <assert.h>
+
+#define AddWinding(eDst,eSrc) (eDst->winding += eSrc->winding, \
+ eDst->Sym->winding += eSrc->Sym->winding)
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * The basic idea is explained in Preparata and Shamos (which I don''t
+ * have handy right now), although their implementation is more
+ * complicated than this one. The are two edge chains, an upper chain
+ * and a lower chain. We process all vertices from both chains in order,
+ * from right to left.
+ *
+ * The algorithm ensures that the following invariant holds after each
+ * vertex is processed: the untessellated region consists of two
+ * chains, where one chain (say the upper) is a single edge, and
+ * the other chain is concave. The left vertex of the single edge
+ * is always to the left of all vertices in the concave chain.
+ *
+ * Each step consists of adding the rightmost unprocessed vertex to one
+ * of the two chains, and forming a fan of triangles from the rightmost
+ * of two chain endpoints. Determining whether we can add each triangle
+ * to the fan is a simple orientation test. By making the fan as large
+ * as possible, we restore the invariant (check it yourself).
+ */
+int __gl_meshTessellateMonoRegion( GLUface *face )
+{
+ GLUhalfEdge *up, *lo;
+
+ /* All edges are oriented CCW around the boundary of the region.
+ * First, find the half-edge whose origin vertex is rightmost.
+ * Since the sweep goes from left to right, face->anEdge should
+ * be close to the edge we want.
+ */
+ up = face->anEdge;
+ assert( up->Lnext != up && up->Lnext->Lnext != up );
+
+ for( ; VertLeq( up->Dst, up->Org ); up = up->Lprev )
+ ;
+ for( ; VertLeq( up->Org, up->Dst ); up = up->Lnext )
+ ;
+ lo = up->Lprev;
+
+ while( up->Lnext != lo ) {
+ if( VertLeq( up->Dst, lo->Org )) {
+ /* up->Dst is on the left. It is safe to form triangles from lo->Org.
+ * The EdgeGoesLeft test guarantees progress even when some triangles
+ * are CW, given that the upper and lower chains are truly monotone.
+ */
+ while( lo->Lnext != up && (EdgeGoesLeft( lo->Lnext )
+ || EdgeSign( lo->Org, lo->Dst, lo->Lnext->Dst ) <= 0 )) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+ if (tempHalfEdge == NULL) return 0;
+ lo = tempHalfEdge->Sym;
+ }
+ lo = lo->Lprev;
+ } else {
+ /* lo->Org is on the left. We can make CCW triangles from up->Dst. */
+ while( lo->Lnext != up && (EdgeGoesRight( up->Lprev )
+ || EdgeSign( up->Dst, up->Org, up->Lprev->Org ) >= 0 )) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( up, up->Lprev );
+ if (tempHalfEdge == NULL) return 0;
+ up = tempHalfEdge->Sym;
+ }
+ up = up->Lnext;
+ }
+ }
+
+ /* Now lo->Org == up->Dst == the leftmost vertex. The remaining region
+ * can be tessellated in a fan from this leftmost vertex.
+ */
+ assert( lo->Lnext != up );
+ while( lo->Lnext->Lnext != up ) {
+ GLUhalfEdge *tempHalfEdge= __gl_meshConnect( lo->Lnext, lo );
+ if (tempHalfEdge == NULL) return 0;
+ lo = tempHalfEdge->Sym;
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ */
+int __gl_meshTessellateInterior( GLUmesh *mesh )
+{
+ GLUface *f, *next;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+ /* Make sure we don''t try to tessellate the new triangles. */
+ next = f->next;
+ if( f->inside ) {
+ if ( !__gl_meshTessellateMonoRegion( f ) ) return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+/* __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ */
+void __gl_meshDiscardExterior( GLUmesh *mesh )
+{
+ GLUface *f, *next;
+
+ /*LINTED*/
+ for( f = mesh->fHead.next; f != &mesh->fHead; f = next ) {
+ /* Since f will be destroyed, save its next pointer. */
+ next = f->next;
+ if( ! f->inside ) {
+ __gl_meshZapFace( f );
+ }
+ }
+}
+
+#define MARKED_FOR_DELETION 0x7fffffff
+
+/* __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+ GLboolean keepOnlyBoundary )
+{
+ GLUhalfEdge *e, *eNext;
+
+ for( e = mesh->eHead.next; e != &mesh->eHead; e = eNext ) {
+ eNext = e->next;
+ if( e->Rface->inside != e->Lface->inside ) {
+
+ /* This is a boundary edge (one side is interior, one is exterior). */
+ e->winding = (e->Lface->inside) ? value : -value;
+ } else {
+
+ /* Both regions are interior, or both are exterior. */
+ if( ! keepOnlyBoundary ) {
+ e->winding = 0;
+ } else {
+ if ( !__gl_meshDelete( e ) ) return 0;
+ }
+ }
+ }
+ return 1;
+}
diff --git a/Source/ThirdParty/glu/libtess/tessmono.h b/Source/ThirdParty/glu/libtess/tessmono.h
new file mode 100644
index 000000000..6a71ee8ed
--- /dev/null
+++ b/Source/ThirdParty/glu/libtess/tessmono.h
@@ -0,0 +1,78 @@
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 1.1 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+*/
+/*
+** Author: Eric Veach, July 1994.
+**
+** $Date$ $Revision$
+** $Header: //depot/main/gfx/lib/glu/libtess/tessmono.h#5 $
+*/
+
+#ifndef __tessmono_h_
+#define __tessmono_h_
+
+/* __gl_meshTessellateMonoRegion( face ) tessellates a monotone region
+ * (what else would it do??) The region must consist of a single
+ * loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
+ * case means that any vertical line intersects the interior of the
+ * region in a single interval.
+ *
+ * Tessellation consists of adding interior edges (actually pairs of
+ * half-edges), to split the region into non-overlapping triangles.
+ *
+ * __gl_meshTessellateInterior( mesh ) tessellates each region of
+ * the mesh which is marked "inside" the polygon. Each such region
+ * must be monotone.
+ *
+ * __gl_meshDiscardExterior( mesh ) zaps (ie. sets to NULL) all faces
+ * which are not marked "inside" the polygon. Since further mesh operations
+ * on NULL faces are not allowed, the main purpose is to clean up the
+ * mesh so that exterior loops are not represented in the data structure.
+ *
+ * __gl_meshSetWindingNumber( mesh, value, keepOnlyBoundary ) resets the
+ * winding numbers on all edges so that regions marked "inside" the
+ * polygon have a winding number of "value", and regions outside
+ * have a winding number of 0.
+ *
+ * If keepOnlyBoundary is TRUE, it also deletes all edges which do not
+ * separate an interior region from an exterior one.
+ */
+
+int __gl_meshTessellateMonoRegion( GLUface *face );
+int __gl_meshTessellateInterior( GLUmesh *mesh );
+void __gl_meshDiscardExterior( GLUmesh *mesh );
+int __gl_meshSetWindingNumber( GLUmesh *mesh, int value,
+ GLboolean keepOnlyBoundary );
+
+#endif
diff --git a/Source/ThirdParty/gtest/CHANGES b/Source/ThirdParty/gtest/CHANGES
new file mode 100644
index 000000000..e574415ee
--- /dev/null
+++ b/Source/ThirdParty/gtest/CHANGES
@@ -0,0 +1,98 @@
+Changes for 1.5.0:
+
+ * New feature: assertions can be safely called in multiple threads
+ where the pthreads library is available.
+ * New feature: predicates used inside EXPECT_TRUE() and friends
+ can now generate custom failure messages.
+ * New feature: Google Test can now be compiled as a DLL.
+ * New feature: fused source files are included.
+ * New feature: prints help when encountering unrecognized Google Test flags.
+ * Experimental feature: CMake build script (requires CMake 2.6.4+).
+ * Experimental feature: the Pump script for meta programming.
+ * double values streamed to an assertion are printed with enough precision
+ to differentiate any two different values.
+ * Google Test now works on Solaris and AIX.
+ * Build and test script improvements.
+ * Bug fixes and implementation clean-ups.
+
+ Potentially breaking changes:
+
+ * Stopped supporting VC++ 7.1 with exceptions disabled.
+ * Dropped support for 'make install'.
+
+Changes for 1.4.0:
+
+ * New feature: the event listener API
+ * New feature: test shuffling
+ * New feature: the XML report format is closer to junitreport and can
+ be parsed by Hudson now.
+ * New feature: when a test runs under Visual Studio, its failures are
+ integrated in the IDE.
+ * New feature: /MD(d) versions of VC++ projects.
+ * New feature: elapsed time for the tests is printed by default.
+ * New feature: comes with a TR1 tuple implementation such that Boost
+ is no longer needed for Combine().
+ * New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends.
+ * New feature: the Xcode project can now produce static gtest
+ libraries in addition to a framework.
+ * Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile,
+ Symbian, gcc, and C++Builder.
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.3.0:
+
+ * New feature: death tests on Windows, Cygwin, and Mac.
+ * New feature: ability to use Google Test assertions in other testing
+ frameworks.
+ * New feature: ability to run disabled test via
+ --gtest_also_run_disabled_tests.
+ * New feature: the --help flag for printing the usage.
+ * New feature: access to Google Test flag values in user code.
+ * New feature: a script that packs Google Test into one .h and one
+ .cc file for easy deployment.
+ * New feature: support for distributing test functions to multiple
+ machines (requires support from the test runner).
+ * Bug fixes and implementation clean-ups.
+
+Changes for 1.2.1:
+
+ * Compatibility fixes for Linux IA-64 and IBM z/OS.
+ * Added support for using Boost and other TR1 implementations.
+ * Changes to the build scripts to support upcoming release of Google C++
+ Mocking Framework.
+ * Added Makefile to the distribution package.
+ * Improved build instructions in README.
+
+Changes for 1.2.0:
+
+ * New feature: value-parameterized tests.
+ * New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS)
+ macros.
+ * Changed the XML report format to match JUnit/Ant's.
+ * Added tests to the Xcode project.
+ * Added scons/SConscript for building with SCons.
+ * Added src/gtest-all.cc for building Google Test from a single file.
+ * Fixed compatibility with Solaris and z/OS.
+ * Enabled running Python tests on systems with python 2.3 installed,
+ e.g. Mac OS X 10.4.
+ * Bug fixes.
+
+Changes for 1.1.0:
+
+ * New feature: type-parameterized tests.
+ * New feature: exception assertions.
+ * New feature: printing elapsed time of tests.
+ * Improved the robustness of death tests.
+ * Added an Xcode project and samples.
+ * Adjusted the output format on Windows to be understandable by Visual Studio.
+ * Minor bug fixes.
+
+Changes for 1.0.1:
+
+ * Added project files for Visual Studio 7.1.
+ * Fixed issues with compiling on Mac OS X.
+ * Fixed issues with compiling on Cygwin.
+
+Changes for 1.0.0:
+
+ * Initial Open Source release of Google Test
diff --git a/Source/ThirdParty/gtest/CMakeLists.txt b/Source/ThirdParty/gtest/CMakeLists.txt
new file mode 100644
index 000000000..7910b5df2
--- /dev/null
+++ b/Source/ThirdParty/gtest/CMakeLists.txt
@@ -0,0 +1,384 @@
+########################################################################
+# Experimental CMake build script for Google Test.
+#
+# Consider this a prototype. It will change drastically. For now,
+# this is only for people on the cutting edge.
+#
+# To run the tests for Google Test itself on Linux, use 'make test' or
+# ctest. You can select which tests to run using 'ctest -R regex'.
+# For more options, run 'ctest --help'.
+
+# For hermetic builds, we may need to tell CMake to use compiler in a
+# specific location.
+if (gtest_compiler)
+ include(CMakeForceCompiler)
+ cmake_force_c_compiler("${gtest_compiler}" "")
+ cmake_force_cxx_compiler("${gtest_compiler}" "")
+endif()
+
+########################################################################
+#
+# Project-wide settings
+
+# Name of the project.
+#
+# CMake files in this project can refer to the root source directory
+# as ${gtest_SOURCE_DIR} and to the root binary directory as
+# ${gtest_BINARY_DIR}.
+# Language "C" is required for find_package(Threads).
+project(gtest CXX C)
+cmake_minimum_required(VERSION 2.6.4)
+
+if (MSVC)
+ # For MSVC, CMake sets certain flags to defaults we want to override.
+ # This replacement code is taken from sample in the CMake Wiki at
+ # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace.
+ foreach (flag_var
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ # In hermetic build environments, tests may not have access to MS runtime
+ # DLLs, so this replaces /MD (CRT libraries in DLLs) with /MT (static CRT
+ # libraries).
+ string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")
+ # We prefer more strict warning checking for building Google Test.
+ # Replaces /W3 with /W4 in defaults.
+ string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}")
+ endforeach()
+endif()
+
+# Where gtest's .h files can be found.
+include_directories(
+ ${gtest_SOURCE_DIR}/include
+ ${gtest_SOURCE_DIR})
+
+# Where the gtest libraries can be found.
+link_directories(
+ ${gtest_BINARY_DIR}/src)
+
+# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
+find_package(Threads)
+
+# Defines the compiler/linker flags used to build gtest. You can
+# tweak these definitions to suit your need. A variable's value is
+# empty before it's explicitly assigned to.
+
+if (MSVC)
+ # Newlines inside flags variables break CMake's NMake generator.
+ set(cxx_base_flags "-GS -W4 -WX -wd4275 -nologo -J -Zi")
+ set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
+ set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
+ set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
+ set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0")
+ set(cxx_no_rtti_flags "-GR-")
+elseif (CMAKE_COMPILER_IS_GNUCXX)
+ set(cxx_base_flags "-Wall -Wshadow")
+ set(cxx_exception_flags "-fexceptions")
+ set(cxx_no_exception_flags "-fno-exceptions")
+ # Until version 4.3.2, GCC doesn't define a macro to indicate
+ # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
+ # explicitly.
+ set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
+ set(cxx_strict_flags "-Wextra")
+elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+ set(cxx_exception_flags "-features=except")
+ # Sun Pro doesn't provide macros to indicate whether exceptions and
+ # RTTI are enabled, so we define GTEST_HAS_* explicitly.
+ set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0")
+ set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0")
+elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR
+ CMAKE_CXX_COMPILER_ID STREQUAL "XL")
+ # CMake 2.8 changes Visual Age's compiler ID to "XL".
+ set(cxx_exception_flags "-qeh")
+ set(cxx_no_exception_flags "-qnoeh")
+ # Until version 9.0, Visual Age doesn't define a macro to indicate
+ # whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
+ # explicitly.
+ set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0")
+endif()
+
+if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available.
+ set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1")
+endif()
+
+# For building gtest's own tests and samples.
+set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}")
+set(cxx_no_exception
+ "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
+set(cxx_default "${cxx_exception}")
+set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}")
+set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1")
+
+# For building the gtest libraries.
+set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
+
+########################################################################
+#
+# Defines the gtest & gtest_main libraries. User tests should link
+# with one of them.
+function(cxx_library_with_type name type cxx_flags)
+ # type can be either STATIC or SHARED to denote a static or shared library.
+ # ARGN refers to additional arguments after 'cxx_flags'.
+ add_library(${name} ${type} ${ARGN})
+ set_target_properties(${name}
+ PROPERTIES
+ COMPILE_FLAGS "${cxx_flags}")
+ if (CMAKE_USE_PTHREADS_INIT)
+ target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT})
+ endif()
+endfunction()
+
+function(cxx_static_library name cxx_flags)
+ cxx_library_with_type(${name} STATIC "${cxx_flags}" ${ARGN})
+endfunction()
+
+function(cxx_shared_library name cxx_flags)
+ cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN})
+endfunction()
+
+function(cxx_library name cxx_flags)
+ # TODO(vladl@google.com): Make static/shared a user option.
+ cxx_static_library(${name} "${cxx_flags}" ${ARGN})
+endfunction()
+
+# Static versions of Google Test libraries. We build them using more
+# strict warnings than what are used for other targets, to ensure that
+# gtest can be compiled by a user aggressive about warnings.
+cxx_static_library(gtest "${cxx_strict}" src/gtest-all.cc)
+cxx_static_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
+target_link_libraries(gtest_main gtest)
+
+########################################################################
+#
+# Samples on how to link user tests with gtest or gtest_main.
+#
+# They are not built by default. To build them, set the
+# build_gtest_samples option to ON. You can do it by running ccmake
+# or specifying the -Dbuild_gtest_samples=ON flag when running cmake.
+
+option(build_gtest_samples "Build gtest's sample programs." OFF)
+
+# cxx_executable_with_flags(name cxx_flags lib srcs...)
+#
+# creates a named C++ executable that depends on the given library and
+# is built from the given source files with the given compiler flags.
+function(cxx_executable_with_flags name cxx_flags lib)
+ add_executable(${name} ${ARGN})
+ if (cxx_flags)
+ set_target_properties(${name}
+ PROPERTIES
+ COMPILE_FLAGS "${cxx_flags}")
+ endif()
+ target_link_libraries(${name} ${lib})
+endfunction()
+
+# cxx_executable(name dir lib srcs...)
+#
+# creates a named target that depends on the given lib and is built
+# from the given source files. dir/name.cc is implicitly included in
+# the source file list.
+function(cxx_executable name dir lib)
+ cxx_executable_with_flags(
+ ${name} "${cxx_default}" ${lib} "${dir}/${name}.cc" ${ARGN})
+endfunction()
+
+if (build_gtest_samples)
+ cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc)
+ cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc)
+ cxx_executable(sample3_unittest samples gtest_main)
+ cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc)
+ cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc)
+ cxx_executable(sample6_unittest samples gtest_main)
+ cxx_executable(sample7_unittest samples gtest_main)
+ cxx_executable(sample8_unittest samples gtest_main)
+ cxx_executable(sample9_unittest samples gtest)
+ cxx_executable(sample10_unittest samples gtest)
+endif()
+
+########################################################################
+#
+# Google Test's own tests.
+#
+# You can skip this section if you aren't interested in testing
+# Google Test itself.
+#
+# Most of the tests are not built by default. To build them, set the
+# build_all_gtest_tests option to ON. You can do it by running ccmake
+# or specifying the -Dbuild_all_gtest_tests=ON flag when running cmake.
+
+option(build_all_gtest_tests "Build all of gtest's own tests." OFF)
+
+# This must be set in the root directory for the tests to be run by
+# 'make test' or ctest.
+enable_testing()
+
+# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE.
+find_package(PythonInterp)
+
+############################################################
+# C++ tests built with standard compiler flags.
+
+# cxx_test_with_flags(name cxx_flags libs srcs...)
+#
+# creates a named C++ test that depends on the given libs and is built
+# from the given source files with the given compiler flags.
+function(cxx_test_with_flags name cxx_flags libs)
+ add_executable(${name} ${ARGN})
+ set_target_properties(${name}
+ PROPERTIES
+ COMPILE_FLAGS "${cxx_flags}")
+ # To support mixing linking in static and dynamic libraries, link each
+ # library in with an extra call to target_link_libraries.
+ foreach (lib "${libs}")
+ target_link_libraries(${name} ${lib})
+ endforeach()
+ add_test(${name} ${name})
+endfunction()
+
+# cxx_test(name libs srcs...)
+#
+# creates a named test target that depends on the given libs and is
+# built from the given source files. Unlike cxx_test_with_flags,
+# test/name.cc is already implicitly included in the source file list.
+function(cxx_test name libs)
+ cxx_test_with_flags("${name}" "${cxx_default}" "${libs}"
+ "test/${name}.cc" ${ARGN})
+endfunction()
+
+cxx_test(gtest_unittest gtest_main)
+
+if (build_all_gtest_tests)
+ cxx_test(gtest-death-test_test gtest_main)
+ cxx_test(gtest_environment_test gtest)
+ cxx_test(gtest-filepath_test gtest_main)
+ cxx_test(gtest-linked_ptr_test gtest_main)
+ cxx_test(gtest-listener_test gtest_main)
+ cxx_test(gtest_main_unittest gtest_main)
+ cxx_test(gtest-message_test gtest_main)
+ cxx_test(gtest_no_test_unittest gtest)
+ cxx_test(gtest-options_test gtest_main)
+ cxx_test(gtest-param-test_test gtest
+ test/gtest-param-test2_test.cc)
+ cxx_test(gtest-port_test gtest_main)
+ cxx_test(gtest_pred_impl_unittest gtest_main)
+ cxx_test(gtest_prod_test gtest_main
+ test/production.cc)
+ cxx_test(gtest_repeat_test gtest)
+ cxx_test(gtest_sole_header_test gtest_main)
+ cxx_test(gtest_stress_test gtest)
+ cxx_test(gtest-test-part_test gtest_main)
+ cxx_test(gtest_throw_on_failure_ex_test gtest)
+ cxx_test(gtest-typed-test_test gtest_main
+ test/gtest-typed-test2_test.cc)
+ cxx_test(gtest-unittest-api_test gtest)
+endif()
+
+############################################################
+# C++ tests built with non-standard compiler flags.
+
+if (build_all_gtest_tests)
+ cxx_library(gtest_no_exception "${cxx_no_exception}"
+ src/gtest-all.cc)
+ cxx_library(gtest_main_no_rtti "${cxx_no_rtti}"
+ src/gtest-all.cc src/gtest_main.cc)
+
+ cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
+ gtest_main_no_rtti test/gtest_unittest.cc)
+
+ set(cxx_use_shared_gtest "${cxx_default} -DGTEST_LINKED_AS_SHARED_LIBRARY=1")
+ set(cxx_build_shared_gtest "${cxx_default} -DGTEST_CREATE_SHARED_LIBRARY=1")
+ if (MSVC)
+ # Disables the "class 'X' needs to have dll-interface to be used
+ # by clients of class 'Y'" warning. This particularly concerns generic
+ # classes like vector that MS doesn't mark as exported.
+ set(cxx_use_shared_gtest "${cxx_use_shared_gtest} -wd4251")
+ set(cxx_build_shared_gtest "${cxx_build_shared_gtest} -wd4251")
+ endif()
+
+ cxx_shared_library(gtest_dll "${cxx_build_shared_gtest}"
+ src/gtest-all.cc)
+
+ # TODO(vladl): This and the next tests may not run in the hermetic
+ # environment on Windows. Re-evaluate and possibly make them
+ # platform-conditional after implementing hermetic builds.
+ cxx_executable_with_flags(gtest_dll_test_ "${cxx_use_shared_gtest}"
+ gtest_dll test/gtest_all_test.cc)
+
+ if (NOT(MSVC AND (MSVC_VERSION EQUAL 1600)))
+ # The C++ Standard specifies tuple_element<int, class>.
+ # Yet MSVC 10's <utility> declares tuple_element<size_t, class>.
+ # That declaration conflicts with our own standard-conforming
+ # tuple implementation. Therefore using our own tuple with
+ # MSVC 10 doesn't compile.
+ cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}"
+ src/gtest-all.cc src/gtest_main.cc)
+
+ cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}"
+ gtest_main_use_own_tuple test/gtest-tuple_test.cc)
+
+ cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}"
+ gtest_main_use_own_tuple
+ test/gtest-param-test_test.cc test/gtest-param-test2_test.cc)
+ endif()
+
+endif()
+
+############################################################
+# Python tests.
+
+# py_test(name)
+#
+# creates a Python test with the given name whose main module is in
+# test/name.py. It does nothing if Python is not installed.
+function(py_test name)
+ if (PYTHONINTERP_FOUND)
+ # ${gtest_BINARY_DIR} is known at configuration time, so we can
+ # directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known
+ # only at ctest runtime (by calling ctest -c <Configuration>), so
+ # we have to escape $ to delay variable substitution here.
+ add_test(${name}
+ ${PYTHON_EXECUTABLE} ${gtest_SOURCE_DIR}/test/${name}.py
+ --gtest_build_dir=${gtest_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE})
+ endif()
+endfunction()
+
+if (build_all_gtest_tests)
+ cxx_executable(gtest_break_on_failure_unittest_ test gtest)
+ py_test(gtest_break_on_failure_unittest)
+
+ cxx_executable(gtest_color_test_ test gtest)
+ py_test(gtest_color_test)
+
+ cxx_executable(gtest_env_var_test_ test gtest)
+ py_test(gtest_env_var_test)
+
+ cxx_executable(gtest_filter_unittest_ test gtest)
+ py_test(gtest_filter_unittest)
+
+ cxx_executable(gtest_help_test_ test gtest_main)
+ py_test(gtest_help_test)
+
+ cxx_executable(gtest_list_tests_unittest_ test gtest)
+ py_test(gtest_list_tests_unittest)
+
+ cxx_executable(gtest_output_test_ test gtest)
+ py_test(gtest_output_test)
+
+ cxx_executable(gtest_shuffle_test_ test gtest)
+ py_test(gtest_shuffle_test)
+
+ cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception)
+ set_target_properties(gtest_throw_on_failure_test_
+ PROPERTIES
+ COMPILE_FLAGS "${cxx_no_exception}")
+ py_test(gtest_throw_on_failure_test)
+
+ cxx_executable(gtest_uninitialized_test_ test gtest)
+ py_test(gtest_uninitialized_test)
+
+ cxx_executable(gtest_xml_outfile1_test_ test gtest_main)
+ cxx_executable(gtest_xml_outfile2_test_ test gtest_main)
+ py_test(gtest_xml_outfiles_test)
+
+ cxx_executable(gtest_xml_output_unittest_ test gtest)
+ py_test(gtest_xml_output_unittest)
+endif()
diff --git a/Source/ThirdParty/gtest/CONTRIBUTORS b/Source/ThirdParty/gtest/CONTRIBUTORS
new file mode 100644
index 000000000..0934ae130
--- /dev/null
+++ b/Source/ThirdParty/gtest/CONTRIBUTORS
@@ -0,0 +1,36 @@
+# This file contains a list of people who've made non-trivial
+# contribution to the Google C++ Testing Framework project. People
+# who commit code to the project are encouraged to add their names
+# here. Please keep the list sorted by first names.
+
+Ajay Joshi <jaj@google.com>
+Balázs Dán <balazs.dan@gmail.com>
+Bharat Mediratta <bharat@menalto.com>
+Chandler Carruth <chandlerc@google.com>
+Chris Prince <cprince@google.com>
+Chris Taylor <taylorc@google.com>
+Dan Egnor <egnor@google.com>
+Eric Roman <eroman@chromium.org>
+Hady Zalek <hady.zalek@gmail.com>
+Jeffrey Yasskin <jyasskin@google.com>
+Jói Sigurðsson <joi@google.com>
+Keir Mierle <mierle@gmail.com>
+Keith Ray <keith.ray@gmail.com>
+Kenton Varda <kenton@google.com>
+Manuel Klimek <klimek@google.com>
+Markus Heule <markus.heule@gmail.com>
+Mika Raento <mikie@iki.fi>
+Miklós Fazekas <mfazekas@szemafor.com>
+Patrick Hanna <phanna@google.com>
+Patrick Riley <pfr@google.com>
+Peter Kaminski <piotrk@google.com>
+Preston Jackson <preston.a.jackson@gmail.com>
+Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com>
+Russ Cox <rsc@google.com>
+Russ Rufer <russ@pentad.com>
+Sean Mcafee <eefacm@gmail.com>
+Sigurður Ásgeirsson <siggi@google.com>
+Tracy Bialik <tracy@pentad.com>
+Vadim Berman <vadimb@google.com>
+Vlad Losev <vladl@google.com>
+Zhanyong Wan <wan@google.com>
diff --git a/Source/ThirdParty/gtest/COPYING b/Source/ThirdParty/gtest/COPYING
new file mode 100644
index 000000000..1941a11f8
--- /dev/null
+++ b/Source/ThirdParty/gtest/COPYING
@@ -0,0 +1,28 @@
+Copyright 2008, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Source/ThirdParty/gtest/Makefile.am b/Source/ThirdParty/gtest/Makefile.am
new file mode 100644
index 000000000..8d75e32cc
--- /dev/null
+++ b/Source/ThirdParty/gtest/Makefile.am
@@ -0,0 +1,284 @@
+# Automake file
+
+# Nonstandard package files for distribution
+EXTRA_DIST = \
+ CHANGES \
+ CONTRIBUTORS \
+ include/gtest/gtest-param-test.h.pump \
+ include/gtest/internal/gtest-tuple.h.pump \
+ include/gtest/internal/gtest-type-util.h.pump \
+ include/gtest/internal/gtest-param-util-generated.h.pump \
+ make/Makefile \
+ scripts/fuse_gtest_files.py \
+ scripts/gen_gtest_pred_impl.py \
+ scripts/pump.py \
+ scripts/test/Makefile
+
+# gtest source files that we don't compile directly. They are
+# #included by gtest-all.cc.
+GTEST_SRC = \
+ src/gtest.cc \
+ src/gtest-death-test.cc \
+ src/gtest-filepath.cc \
+ src/gtest-internal-inl.h \
+ src/gtest-port.cc \
+ src/gtest-test-part.cc \
+ src/gtest-typed-test.cc
+
+EXTRA_DIST += $(GTEST_SRC)
+
+# Sample files that we don't compile.
+EXTRA_DIST += \
+ samples/prime_tables.h \
+ samples/sample2_unittest.cc \
+ samples/sample3_unittest.cc \
+ samples/sample4_unittest.cc \
+ samples/sample5_unittest.cc \
+ samples/sample6_unittest.cc \
+ samples/sample7_unittest.cc \
+ samples/sample8_unittest.cc \
+ samples/sample9_unittest.cc
+
+# C++ test files that we don't compile directly.
+EXTRA_DIST += \
+ test/gtest-death-test_test.cc \
+ test/gtest_environment_test.cc \
+ test/gtest-filepath_test.cc \
+ test/gtest-linked_ptr_test.cc \
+ test/gtest-message_test.cc \
+ test/gtest_no_test_unittest.cc \
+ test/gtest-options_test.cc \
+ test/gtest-param-test_test.cc \
+ test/gtest-param-test2_test.cc \
+ test/gtest-param-test_test.h \
+ test/gtest-port_test.cc \
+ test/gtest_pred_impl_unittest.cc \
+ test/gtest_prod_test.cc \
+ test/production.cc \
+ test/production.h \
+ test/gtest_repeat_test.cc \
+ test/gtest_sole_header_test.cc \
+ test/gtest_stress_test.cc \
+ test/gtest-test-part_test.cc \
+ test/gtest_throw_on_failure_ex_test.cc \
+ test/gtest-typed-test_test.cc \
+ test/gtest-typed-test2_test.cc \
+ test/gtest-typed-test_test.h \
+ test/gtest_unittest.cc \
+ test/gtest-unittest-api_test.cc \
+ test/gtest-listener_test.cc \
+ test/gtest_main_unittest.cc \
+ test/gtest_unittest.cc \
+ test/gtest-tuple_test.cc \
+ test/gtest-param-test_test.cc \
+ test/gtest-param-test2_test.cc \
+ test/gtest_break_on_failure_unittest_.cc \
+ test/gtest_color_test_.cc \
+ test/gtest_env_var_test_.cc \
+ test/gtest_filter_unittest_.cc \
+ test/gtest_help_test_.cc \
+ test/gtest_list_tests_unittest_.cc \
+ test/gtest_output_test_.cc \
+ test/gtest_shuffle_test_.cc \
+ test/gtest_throw_on_failure_test_.cc \
+ test/gtest_uninitialized_test_.cc \
+ test/gtest_xml_outfile1_test_.cc \
+ test/gtest_xml_outfile2_test_.cc \
+ test/gtest_xml_output_unittest_.cc
+
+# Python tests that we don't run.
+EXTRA_DIST += \
+ test/gtest_test_utils.py \
+ test/gtest_xml_test_utils.py \
+ test/gtest_break_on_failure_unittest.py \
+ test/gtest_color_test.py \
+ test/gtest_env_var_test.py \
+ test/gtest_filter_unittest.py \
+ test/gtest_help_test.py \
+ test/gtest_list_tests_unittest.py \
+ test/gtest_output_test.py \
+ test/gtest_output_test_golden_lin.txt \
+ test/gtest_output_test_golden_win.txt \
+ test/gtest_shuffle_test.py \
+ test/gtest_throw_on_failure_test.py \
+ test/gtest_uninitialized_test.py \
+ test/gtest_xml_outfiles_test.py \
+ test/gtest_xml_output_unittest.py \
+ test/run_tests_util.py \
+ test/run_tests_util_test.py
+
+# CMake script
+EXTRA_DIST += \
+ CMakeLists.txt
+
+# MSVC project files
+EXTRA_DIST += \
+ msvc/gtest-md.sln \
+ msvc/gtest.sln \
+ msvc/gtest-md.vcproj \
+ msvc/gtest.vcproj \
+ msvc/gtest_main-md.vcproj \
+ msvc/gtest_main.vcproj \
+ msvc/gtest_prod_test-md.vcproj \
+ msvc/gtest_prod_test.vcproj \
+ msvc/gtest_unittest-md.vcproj \
+ msvc/gtest_unittest.vcproj
+
+# xcode project files
+EXTRA_DIST += \
+ xcode/Config/DebugProject.xcconfig \
+ xcode/Config/FrameworkTarget.xcconfig \
+ xcode/Config/General.xcconfig \
+ xcode/Config/ReleaseProject.xcconfig \
+ xcode/Config/StaticLibraryTarget.xcconfig \
+ xcode/Config/TestTarget.xcconfig \
+ xcode/Resources/Info.plist \
+ xcode/Scripts/versiongenerate.py \
+ xcode/Scripts/runtests.sh \
+ xcode/gtest.xcodeproj/project.pbxproj
+
+# xcode sample files
+EXTRA_DIST += \
+ xcode/Samples/FrameworkSample/Info.plist \
+ xcode/Samples/FrameworkSample/runtests.sh \
+ xcode/Samples/FrameworkSample/widget_test.cc \
+ xcode/Samples/FrameworkSample/widget.cc \
+ xcode/Samples/FrameworkSample/widget.h \
+ xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj
+
+# C++Builder project files
+EXTRA_DIST += \
+ codegear/gtest_all.cc \
+ codegear/gtest_link.cc \
+ codegear/gtest.cbproj \
+ codegear/gtest_main.cbproj \
+ codegear/gtest_unittest.cbproj \
+ codegear/gtest.groupproj
+
+# Scripts and utilities
+bin_SCRIPTS = scripts/gtest-config
+CLEANFILES = $(bin_SCRIPTS)
+
+# Distribute and install M4 macro
+m4datadir = $(datadir)/aclocal
+m4data_DATA = m4/gtest.m4
+EXTRA_DIST += $(m4data_DATA)
+
+# We define the global AM_CPPFLAGS as everything we compile includes from these
+# directories.
+AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include
+
+# Modifies compiler and linker flags for pthreads compatibility.
+if HAVE_PTHREADS
+ AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1
+ AM_LIBS = @PTHREAD_LIBS@
+else
+ AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0
+endif
+
+# Build rules for libraries.
+lib_LTLIBRARIES = lib/libgtest.la lib/libgtest_main.la
+
+lib_libgtest_la_SOURCES = src/gtest-all.cc
+
+pkginclude_HEADERS = include/gtest/gtest.h \
+ include/gtest/gtest-death-test.h \
+ include/gtest/gtest-message.h \
+ include/gtest/gtest-param-test.h \
+ include/gtest/gtest_pred_impl.h \
+ include/gtest/gtest_prod.h \
+ include/gtest/gtest-spi.h \
+ include/gtest/gtest-test-part.h \
+ include/gtest/gtest-typed-test.h
+
+pkginclude_internaldir = $(pkgincludedir)/internal
+pkginclude_internal_HEADERS = \
+ include/gtest/internal/gtest-death-test-internal.h \
+ include/gtest/internal/gtest-filepath.h \
+ include/gtest/internal/gtest-internal.h \
+ include/gtest/internal/gtest-linked_ptr.h \
+ include/gtest/internal/gtest-param-util-generated.h \
+ include/gtest/internal/gtest-param-util.h \
+ include/gtest/internal/gtest-port.h \
+ include/gtest/internal/gtest-string.h \
+ include/gtest/internal/gtest-tuple.h \
+ include/gtest/internal/gtest-type-util.h
+
+lib_libgtest_main_la_SOURCES = src/gtest_main.cc
+lib_libgtest_main_la_LIBADD = lib/libgtest.la
+
+# Bulid rules for samples and tests. Automake's naming for some of
+# these variables isn't terribly obvious, so this is a brief
+# reference:
+#
+# TESTS -- Programs run automatically by "make check"
+# check_PROGRAMS -- Programs built by "make check" but not necessarily run
+
+noinst_LTLIBRARIES = samples/libsamples.la
+
+samples_libsamples_la_SOURCES = samples/sample1.cc \
+ samples/sample1.h \
+ samples/sample2.cc \
+ samples/sample2.h \
+ samples/sample3-inl.h \
+ samples/sample4.cc \
+ samples/sample4.h
+
+TESTS=
+TESTS_ENVIRONMENT = GTEST_SOURCE_DIR="$(srcdir)/test" \
+ GTEST_BUILD_DIR="$(top_builddir)/test"
+check_PROGRAMS=
+
+# A simple sample on using gtest.
+TESTS += samples/sample1_unittest
+check_PROGRAMS += samples/sample1_unittest
+samples_sample1_unittest_SOURCES = samples/sample1_unittest.cc
+samples_sample1_unittest_LDADD = lib/libgtest_main.la \
+ samples/libsamples.la
+
+# Another sample. It also verifies that libgtest works.
+TESTS += samples/sample10_unittest
+check_PROGRAMS += samples/sample10_unittest
+samples_sample10_unittest_SOURCES = samples/sample10_unittest.cc
+samples_sample10_unittest_LDADD = lib/libgtest.la
+
+# This tests most constructs of gtest and verifies that libgtest_main
+# works.
+TESTS += test/gtest_all_test
+check_PROGRAMS += test/gtest_all_test
+test_gtest_all_test_SOURCES = test/gtest_all_test.cc
+test_gtest_all_test_LDADD = lib/libgtest_main.la
+
+# Tests that fused gtest files compile and work.
+FUSED_GTEST_SRC = \
+ fused-src/gtest/gtest-all.cc \
+ fused-src/gtest/gtest_main.cc \
+ fused-src/gtest/gtest.h
+
+TESTS += test/fused_gtest_test
+check_PROGRAMS += test/fused_gtest_test
+test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \
+ samples/sample1.cc samples/sample1_unittest.cc
+test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src"
+
+# Build rules for putting fused Google Test files into the distribution
+# package. The user can also create those files by manually running
+# scripts/fuse_gtest_files.py.
+$(test_fused_gtest_test_SOURCES): fused-gtest
+
+fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
+ $(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \
+ scripts/fuse_gtest_files.py
+ mkdir -p "$(srcdir)/fused-src"
+ chmod -R u+w "$(srcdir)/fused-src"
+ rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc"
+ rm -f "$(srcdir)/fused-src/gtest/gtest.h"
+ "$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src"
+ cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/"
+
+maintainer-clean-local:
+ rm -rf "$(srcdir)/fused-src"
+
+# Death tests may produce core dumps in the build directory. In case
+# this happens, clean them to keep distcleancheck happy.
+CLEANFILES += core
diff --git a/Source/ThirdParty/gtest/README b/Source/ThirdParty/gtest/README
new file mode 100644
index 000000000..ec6119002
--- /dev/null
+++ b/Source/ThirdParty/gtest/README
@@ -0,0 +1,417 @@
+Google C++ Testing Framework
+============================
+
+http://code.google.com/p/googletest/
+
+Overview
+--------
+
+Google's framework for writing C++ tests on a variety of platforms
+(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the
+xUnit architecture. Supports automatic test discovery, a rich set of
+assertions, user-defined assertions, death tests, fatal and non-fatal
+failures, various options for running the tests, and XML test report
+generation.
+
+Please see the project page above for more information as well as the
+mailing list for questions, discussions, and development. There is
+also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
+join us!
+
+Requirements for End Users
+--------------------------
+
+Google Test is designed to have fairly minimal requirements to build
+and use with your projects, but there are some. Currently, we support
+Linux, Windows, Mac OS X, and Cygwin. We will also make our best
+effort to support other platforms (e.g. Solaris, AIX, and z/OS).
+However, since core members of the Google Test project have no access
+to these platforms, Google Test may have outstanding issues there. If
+you notice any problems on your platform, please notify
+googletestframework@googlegroups.com. Patches for fixing them are
+even more welcome!
+
+### Linux Requirements ###
+
+These are the base requirements to build and use Google Test from a source
+package (as described below):
+ * GNU-compatible Make or gmake
+ * POSIX-standard shell
+ * POSIX(-2) Regular Expressions (regex.h)
+ * A C++98-standard-compliant compiler
+
+### Windows Requirements ###
+
+ * Microsoft Visual C++ 7.1 or newer
+
+### Cygwin Requirements ###
+
+ * Cygwin 1.5.25-14 or newer
+
+### Mac OS X Requirements ###
+
+ * Mac OS X 10.4 Tiger or newer
+ * Developer Tools Installed
+
+Also, you'll need CMake 2.6.4 or higher if you want to build the
+samples using the provided CMake script, regardless of the platform.
+
+Requirements for Contributors
+-----------------------------
+
+We welcome patches. If you plan to contribute a patch, you need to
+build Google Test and its own tests from an SVN checkout (described
+below), which has further requirements:
+
+ * Python version 2.3 or newer (for running some of the tests and
+ re-generating certain source files from templates)
+ * CMake 2.6.4 or newer
+
+Getting the Source
+------------------
+
+There are two primary ways of getting Google Test's source code: you
+can download a stable source release in your preferred archive format,
+or directly check out the source from our Subversion (SVN) repositary.
+The SVN checkout requires a few extra steps and some extra software
+packages on your system, but lets you track the latest development and
+make patches much more easily, so we highly encourage it.
+
+### Source Package ###
+
+Google Test is released in versioned source packages which can be
+downloaded from the download page [1]. Several different archive
+formats are provided, but the only difference is the tools used to
+manipulate them, and the size of the resulting file. Download
+whichever you are most comfortable with.
+
+ [1] http://code.google.com/p/googletest/downloads/list
+
+Once the package is downloaded, expand it using whichever tools you
+prefer for that type. This will result in a new directory with the
+name "gtest-X.Y.Z" which contains all of the source code. Here are
+some examples on Linux:
+
+ tar -xvzf gtest-X.Y.Z.tar.gz
+ tar -xvjf gtest-X.Y.Z.tar.bz2
+ unzip gtest-X.Y.Z.zip
+
+### SVN Checkout ###
+
+To check out the main branch (also known as the "trunk") of Google
+Test, run the following Subversion command:
+
+ svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
+
+Setting up the Build
+--------------------
+
+To build Google Test and your tests that use it, you need to tell your
+build system where to find its headers and source files. The exact
+way to do it depends on which build system you use, and is usually
+straightforward.
+
+### Generic Build Instructions ###
+
+Suppose you put Google Test in directory ${GTEST_DIR}. To build it,
+create a library build target (or a project as called by Visual Studio
+and Xcode) to compile
+
+ ${GTEST_DIR}/src/gtest-all.cc
+
+with
+
+ ${GTEST_DIR}/include and ${GTEST_DIR}
+
+in the header search path. Assuming a Linux-like system and gcc,
+something like the following will do:
+
+ g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
+ ar -rv libgtest.a gtest-all.o
+
+Next, you should compile your test source file with
+${GTEST_DIR}/include in the header search path, and link it with gtest
+and any other necessary libraries:
+
+ g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test
+
+As an example, the make/ directory contains a Makefile that you can
+use to build Google Test on systems where GNU make is available
+(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
+Test's own tests. Instead, it just builds the Google Test library and
+a sample test. You can use it as a starting point for your own build
+script.
+
+If the default settings are correct for your environment, the
+following commands should succeed:
+
+ cd ${GTEST_DIR}/make
+ make
+ ./sample1_unittest
+
+If you see errors, try to tweak the contents of make/Makefile to make
+them go away. There are instructions in make/Makefile on how to do
+it.
+
+### Using CMake ###
+
+Google Test comes with a CMake build script (CMakeLists.txt) that can
+be used on a wide range of platforms ("C" stands for cross-platofrm.).
+If you don't have CMake installed already, you can download it for
+free from http://www.cmake.org/.
+
+CMake works by generating native makefiles or build projects that can
+be used in the compiler environment of your choice. The typical
+workflow starts with:
+
+ mkdir mybuild # Create a directory to hold the build output.
+ cd mybuild
+ cmake ${GTEST_DIR} # Generate native build scripts.
+
+If you want to build Google Test's samples, you should replace the
+last command with
+
+ cmake -Dbuild_gtest_samples=ON ${GTEST_DIR}
+
+If you are on a *nix system, you should now see a Makefile in the
+current directory. Just type 'make' to build gtest.
+
+If you use Windows and have Vistual Studio installed, a gtest.sln file
+and several .vcproj files will be created. You can then build them
+using Visual Studio.
+
+On Mac OS X with Xcode installed, a .xcodeproj file will be generated.
+
+### Legacy Build Scripts ###
+
+Before settling on CMake, we have been providing hand-maintained build
+projects/scripts for Visual Studio, Xcode, and Autotools. While we
+continue to provide them for convenience, they are not actively
+maintained any more. We highly recommend that you follow the
+instructions in the previous two sections to integrate Google Test
+with your existing build system.
+
+If you still need to use the legacy build scripts, here's how:
+
+The msvc\ folder contains two solutions with Visual C++ projects.
+Open the gtest.sln or gtest-md.sln file using Visual Studio, and you
+are ready to build Google Test the same way you build any Visual
+Studio project. Files that have names ending with -md use DLL
+versions of Microsoft runtime libraries (the /MD or the /MDd compiler
+option). Files without that suffix use static versions of the runtime
+libraries (the /MT or the /MTd option). Please note that one must use
+the same option to compile both gtest and the test code. If you use
+Visual Studio 2005 or above, we recommend the -md version as /MD is
+the default for new projects in these versions of Visual Studio.
+
+On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using
+Xcode. Build the "gtest" target. The universal binary framework will
+end up in your selected build directory (selected in the Xcode
+"Preferences..." -> "Building" pane and defaults to xcode/build).
+Alternatively, at the command line, enter:
+
+ xcodebuild
+
+This will build the "Release" configuration of gtest.framework in your
+default build location. See the "xcodebuild" man page for more
+information about building different configurations and building in
+different locations.
+
+Tweaking Google Test
+--------------------
+
+Google Test can be used in diverse environments. The default
+configuration may not work (or may not work well) out of the box in
+some environments. However, you can easily tweak Google Test by
+defining control macros on the compiler command line. Generally,
+these macros are named like GTEST_XYZ and you define them to either 1
+or 0 to enable or disable a certain feature.
+
+We list the most frequently used macros below. For a complete list,
+see file include/gtest/internal/gtest-port.h.
+
+### Choosing a TR1 Tuple Library ###
+
+Some Google Test features require the C++ Technical Report 1 (TR1)
+tuple library, which is not yet available with all compilers. The
+good news is that Google Test implements a subset of TR1 tuple that's
+enough for its own need, and will automatically use this when the
+compiler doesn't provide TR1 tuple.
+
+Usually you don't need to care about which tuple library Google Test
+uses. However, if your project already uses TR1 tuple, you need to
+tell Google Test to use the same TR1 tuple library the rest of your
+project uses, or the two tuple implementations will clash. To do
+that, add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=0
+
+to the compiler flags while compiling Google Test and your tests. If
+you want to force Google Test to use its own tuple library, just add
+
+ -DGTEST_USE_OWN_TR1_TUPLE=1
+
+to the compiler flags instead.
+
+If you don't want Google Test to use tuple at all, add
+
+ -DGTEST_HAS_TR1_TUPLE=0
+
+and all features using tuple will be disabled.
+
+### Multi-threaded Tests ###
+
+Google Test is thread-safe where the pthread library is available.
+After #include <gtest/gtest.h>, you can check the GTEST_IS_THREADSAFE
+macro to see whether this is the case (yes if the macro is #defined to
+1, no if it's undefined.).
+
+If Google Test doesn't correctly detect whether pthread is available
+in your environment, you can force it with
+
+ -DGTEST_HAS_PTHREAD=1
+
+or
+
+ -DGTEST_HAS_PTHREAD=0
+
+When Google Test uses pthread, you may need to add flags to your
+compiler and/or linker to select the pthread library, or you'll get
+link errors. If you use the CMake script or the deprecated Autotools
+script, this is taken care of for you. If you use your own build
+script, you'll need to read your compiler and linker's manual to
+figure out what flags to add.
+
+### As a Shared Library (DLL) ###
+
+Google Test is compact, so most users can build and link it as a
+static library for the simplicity. You can choose to use Google Test
+as a shared library (known as a DLL on Windows) if you prefer.
+
+To compile gtest as a shared library, add
+
+ -DGTEST_CREATE_SHARED_LIBRARY=1
+
+to the compiler flags. You'll also need to tell the linker to produce
+a shared library instead - consult your linker's manual for how to do
+it.
+
+To compile your tests that use the gtest shared library, add
+
+ -DGTEST_LINKED_AS_SHARED_LIBRARY=1
+
+to the compiler flags.
+
+### Avoiding Macro Name Clashes ###
+
+In C++, macros don't obey namespaces. Therefore two libraries that
+both define a macro of the same name will clash if you #include both
+definitions. In case a Google Test macro clashes with another
+library, you can force Google Test to rename its macro to avoid the
+conflict.
+
+Specifically, if both Google Test and some other code define macro
+FOO, you can add
+
+ -DGTEST_DONT_DEFINE_FOO=1
+
+to the compiler flags to tell Google Test to change the macro's name
+from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST.
+For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write
+
+ GTEST_TEST(SomeTest, DoesThis) { ... }
+
+instead of
+
+ TEST(SomeTest, DoesThis) { ... }
+
+in order to define a test.
+
+Upgrating from an Earlier Version
+---------------------------------
+
+We strive to keep Google Test releases backward compatible.
+Sometimes, though, we have to make some breaking changes for the
+users' long-term benefits. This section describes what you'll need to
+do if you are upgrading from an earlier version of Google Test.
+
+### Upgrading from 1.3.0 or Earlier ###
+
+You may need to explicitly enable or disable Google Test's own TR1
+tuple library. See the instructions in section "Choosing a TR1 Tuple
+Library".
+
+### Upgrading from 1.4.0 or Earlier ###
+
+The Autotools build script (configure + make) is no longer officially
+supportted. You are encouraged to migrate to your own build system or
+use CMake. If you still need to use Autotools, you can find
+instructions in the README file from Google Test 1.4.0.
+
+On platforms where the pthread library is available, Google Test uses
+it in order to be thread-safe. See the "Multi-threaded Tests" section
+for what this means to your build script.
+
+If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google
+Test will no longer compile. This should affect very few people, as a
+large portion of STL (including <string>) doesn't compile in this mode
+anyway. We decided to stop supporting it in order to greatly simplify
+Google Test's implementation.
+
+Developing Google Test
+----------------------
+
+This section discusses how to make your own changes to Google Test.
+
+### Testing Google Test Itself ###
+
+To make sure your changes work as intended and don't break existing
+functionality, you'll want to compile and run Google Test's own tests.
+For that you can use CMake:
+
+ mkdir mybuild
+ cd mybuild
+ cmake -Dbuild_all_gtest_tests=ON ${GTEST_DIR}
+
+Make sure you have Python installed, as some of Google Test's tests
+are written in Python. If the cmake command complains about not being
+able to find Python ("Could NOT find PythonInterp (missing:
+PYTHON_EXECUTABLE)"), try telling it explicitly where your Python
+executable can be found:
+
+ cmake -DPYTHON_EXECUTABLE=path/to/python -Dbuild_all_gtest_tests=ON \
+ ${GTEST_DIR}
+
+Next, you can build Google Test and all of its own tests. On *nix,
+this is usually done by 'make'. To run the tests, do
+
+ make test
+
+All tests should pass.
+
+### Regenerating Source Files ###
+
+Some of Google Test's source files are generated from templates (not
+in the C++ sense) using a script. A template file is named FOO.pump,
+where FOO is the name of the file it will generate. For example, the
+file include/gtest/internal/gtest-type-util.h.pump is used to generate
+gtest-type-util.h in the same directory.
+
+Normally you don't need to worry about regenerating the source files,
+unless you need to modify them. In that case, you should modify the
+corresponding .pump files instead and run the pump.py Python script to
+regenerate them. You can find pump.py in the scripts/ directory.
+Read the Pump manual [2] for how to use it.
+
+ [2] http://code.google.com/p/googletest/wiki/PumpManual
+
+### Contributing a Patch ###
+
+We welcome patches. Please read the Google Test developer's guide [3]
+for how you can contribute. In particular, make sure you have signed
+the Contributor License Agreement, or we won't be able to accept the
+patch.
+
+ [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide
+
+Happy testing!
diff --git a/Source/ThirdParty/gtest/README.WebKit b/Source/ThirdParty/gtest/README.WebKit
new file mode 100644
index 000000000..acae49d82
--- /dev/null
+++ b/Source/ThirdParty/gtest/README.WebKit
@@ -0,0 +1,13 @@
+GTest v.1.5.0
+
+http://googletest.googlecode.com/svn/tags/release-1.5.0/
+
+2012-01-04 Dmitry Lomov (dslomov@google.com) David Kilzer (ddkilzer@apple.com)
+ - WebKit port of gtest uses FastMalloc "new" and "delete" operators from JavaScriptCore.
+ - The gtest.framework target now links to JavaScriptCore.framework.
+
+2011-12-22 David Kilzer (ddkilzer@apple.com)
+ Added Production configuration to gtest Xcode project.
+
+2011-05-06 Dmitry Lomov (dslomov@google.com)
+ gtest-md.vcproj upgraded to VS 2005 (8.0) format to match the rest of WebKit
diff --git a/Source/ThirdParty/gtest/codegear/gtest.cbproj b/Source/ThirdParty/gtest/codegear/gtest.cbproj
new file mode 100644
index 000000000..95c3054b8
--- /dev/null
+++ b/Source/ThirdParty/gtest/codegear/gtest.cbproj
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
+ <Config Condition="'$(Config)'==''">Release</Config>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+ <Base>true</Base>
+ <Cfg_1>true</Cfg_1>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+ <Base>true</Base>
+ <Cfg_2>true</Cfg_2>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Base)'!=''">
+ <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+ <OutputExt>lib</OutputExt>
+ <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+ <Defines>NO_STRICT</Defines>
+ <DynamicRTL>true</DynamicRTL>
+ <UsePackages>true</UsePackages>
+ <ProjectType>CppStaticLibrary</ProjectType>
+ <BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
+ <PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi</PackageImports>
+ <BCC_wpar>false</BCC_wpar>
+ <IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
+ <AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
+ <TLIB_PageSize>32</TLIB_PageSize>
+ <ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
+ <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+ <DCC_Optimize>false</DCC_Optimize>
+ <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+ <Defines>_DEBUG;$(Defines)</Defines>
+ <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+ <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+ <ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
+ <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+ <DCC_Define>DEBUG</DCC_Define>
+ <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+ <IntermediateOutputDir>Debug</IntermediateOutputDir>
+ <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+ <BCC_StackFrames>true</BCC_StackFrames>
+ <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+ <ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>Full</TASM_Debugging>
+ <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
+ <Defines>NDEBUG;$(Defines)</Defines>
+ <IntermediateOutputDir>Release</IntermediateOutputDir>
+ <ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>None</TASM_Debugging>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
+ <Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
+ <BorlandProject>
+<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
+
+
+ <Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
+ <Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
+ </Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">1</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines><HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Count">1</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item0">32</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item1">16</HistoryLists_hlTLIB_PageSize></HistoryLists_hlTLIB_PageSize></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
+ </ProjectExtensions>
+ <Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
+ <ItemGroup>
+ <None Include="..\include\gtest\gtest-death-test.h">
+ <BuildOrder>3</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-message.h">
+ <BuildOrder>4</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-param-test.h">
+ <BuildOrder>5</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-spi.h">
+ <BuildOrder>6</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-test-part.h">
+ <BuildOrder>7</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest-typed-test.h">
+ <BuildOrder>8</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest.h">
+ <BuildOrder>0</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest_pred_impl.h">
+ <BuildOrder>1</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\gtest_prod.h">
+ <BuildOrder>2</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-death-test-internal.h">
+ <BuildOrder>9</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-filepath.h">
+ <BuildOrder>10</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-internal.h">
+ <BuildOrder>11</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-linked_ptr.h">
+ <BuildOrder>12</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-param-util-generated.h">
+ <BuildOrder>14</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-param-util.h">
+ <BuildOrder>13</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-port.h">
+ <BuildOrder>15</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-string.h">
+ <BuildOrder>16</BuildOrder>
+ </None>
+ <None Include="..\include\gtest\internal\gtest-type-util.h">
+ <BuildOrder>17</BuildOrder>
+ </None>
+ <CppCompile Include="gtest_all.cc">
+ <BuildOrder>18</BuildOrder>
+ </CppCompile>
+ <BuildConfiguration Include="Debug">
+ <Key>Cfg_1</Key>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Release">
+ <Key>Cfg_2</Key>
+ </BuildConfiguration>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Source/ThirdParty/gtest/codegear/gtest.groupproj b/Source/ThirdParty/gtest/codegear/gtest.groupproj
new file mode 100644
index 000000000..faf31cab6
--- /dev/null
+++ b/Source/ThirdParty/gtest/codegear/gtest.groupproj
@@ -0,0 +1,54 @@
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{c1d923e0-6cba-4332-9b6f-3420acbf5091}</ProjectGuid>
+ </PropertyGroup>
+ <ItemGroup />
+ <ItemGroup>
+ <Projects Include="gtest.cbproj" />
+ <Projects Include="gtest_main.cbproj" />
+ <Projects Include="gtest_unittest.cbproj" />
+ </ItemGroup>
+ <ProjectExtensions>
+ <Borland.Personality>Default.Personality</Borland.Personality>
+ <Borland.ProjectType />
+ <BorlandProject>
+<BorlandProject xmlns=""><Default.Personality></Default.Personality></BorlandProject></BorlandProject>
+ </ProjectExtensions>
+ <Target Name="gtest">
+ <MSBuild Projects="gtest.cbproj" Targets="" />
+ </Target>
+ <Target Name="gtest:Clean">
+ <MSBuild Projects="gtest.cbproj" Targets="Clean" />
+ </Target>
+ <Target Name="gtest:Make">
+ <MSBuild Projects="gtest.cbproj" Targets="Make" />
+ </Target>
+ <Target Name="gtest_main">
+ <MSBuild Projects="gtest_main.cbproj" Targets="" />
+ </Target>
+ <Target Name="gtest_main:Clean">
+ <MSBuild Projects="gtest_main.cbproj" Targets="Clean" />
+ </Target>
+ <Target Name="gtest_main:Make">
+ <MSBuild Projects="gtest_main.cbproj" Targets="Make" />
+ </Target>
+ <Target Name="gtest_unittest">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="" />
+ </Target>
+ <Target Name="gtest_unittest:Clean">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="Clean" />
+ </Target>
+ <Target Name="gtest_unittest:Make">
+ <MSBuild Projects="gtest_unittest.cbproj" Targets="Make" />
+ </Target>
+ <Target Name="Build">
+ <CallTarget Targets="gtest;gtest_main;gtest_unittest" />
+ </Target>
+ <Target Name="Clean">
+ <CallTarget Targets="gtest:Clean;gtest_main:Clean;gtest_unittest:Clean" />
+ </Target>
+ <Target Name="Make">
+ <CallTarget Targets="gtest:Make;gtest_main:Make;gtest_unittest:Make" />
+ </Target>
+ <Import Condition="Exists('$(MSBuildBinPath)\Borland.Group.Targets')" Project="$(MSBuildBinPath)\Borland.Group.Targets" />
+</Project> \ No newline at end of file
diff --git a/Source/ThirdParty/gtest/codegear/gtest_all.cc b/Source/ThirdParty/gtest/codegear/gtest_all.cc
new file mode 100644
index 000000000..121b2d80e
--- /dev/null
+++ b/Source/ThirdParty/gtest/codegear/gtest_all.cc
@@ -0,0 +1,38 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Josh Kelley (joshkel@gmail.com)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// C++Builder's IDE cannot build a static library from files with hyphens
+// in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 .
+// This file serves as a workaround.
+
+#include "src/gtest-all.cc"
diff --git a/Source/ThirdParty/gtest/codegear/gtest_link.cc b/Source/ThirdParty/gtest/codegear/gtest_link.cc
new file mode 100644
index 000000000..918eccd19
--- /dev/null
+++ b/Source/ThirdParty/gtest/codegear/gtest_link.cc
@@ -0,0 +1,40 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Josh Kelley (joshkel@gmail.com)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// Links gtest.lib and gtest_main.lib into the current project in C++Builder.
+// This means that these libraries can't be renamed, but it's the only way to
+// ensure that Debug versus Release test builds are linked against the
+// appropriate Debug or Release build of the libraries.
+
+#pragma link "gtest.lib"
+#pragma link "gtest_main.lib"
diff --git a/Source/ThirdParty/gtest/codegear/gtest_main.cbproj b/Source/ThirdParty/gtest/codegear/gtest_main.cbproj
new file mode 100644
index 000000000..d76ce1398
--- /dev/null
+++ b/Source/ThirdParty/gtest/codegear/gtest_main.cbproj
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
+ <Config Condition="'$(Config)'==''">Release</Config>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+ <Base>true</Base>
+ <Cfg_1>true</Cfg_1>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+ <Base>true</Base>
+ <Cfg_2>true</Cfg_2>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Base)'!=''">
+ <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+ <OutputExt>lib</OutputExt>
+ <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+ <Defines>NO_STRICT</Defines>
+ <DynamicRTL>true</DynamicRTL>
+ <UsePackages>true</UsePackages>
+ <ProjectType>CppStaticLibrary</ProjectType>
+ <BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
+ <PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi</PackageImports>
+ <BCC_wpar>false</BCC_wpar>
+ <IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
+ <AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
+ <TLIB_PageSize>32</TLIB_PageSize>
+ <ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
+ <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+ <DCC_Optimize>false</DCC_Optimize>
+ <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+ <Defines>_DEBUG;$(Defines)</Defines>
+ <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+ <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+ <ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
+ <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+ <DCC_Define>DEBUG</DCC_Define>
+ <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+ <IntermediateOutputDir>Debug</IntermediateOutputDir>
+ <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+ <BCC_StackFrames>true</BCC_StackFrames>
+ <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+ <ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>Full</TASM_Debugging>
+ <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
+ <Defines>NDEBUG;$(Defines)</Defines>
+ <IntermediateOutputDir>Release</IntermediateOutputDir>
+ <ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>None</TASM_Debugging>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
+ <Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
+ <BorlandProject>
+<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
+ <Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
+ <Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
+ </Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">1</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines><HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Count">1</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item0">32</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item1">16</HistoryLists_hlTLIB_PageSize></HistoryLists_hlTLIB_PageSize></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
+ </ProjectExtensions>
+ <Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
+ <ItemGroup>
+ <CppCompile Include="..\src\gtest_main.cc">
+ <BuildOrder>0</BuildOrder>
+ </CppCompile>
+ <BuildConfiguration Include="Debug">
+ <Key>Cfg_1</Key>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Release">
+ <Key>Cfg_2</Key>
+ </BuildConfiguration>
+ </ItemGroup>
+</Project>
diff --git a/Source/ThirdParty/gtest/codegear/gtest_unittest.cbproj b/Source/ThirdParty/gtest/codegear/gtest_unittest.cbproj
new file mode 100644
index 000000000..dc5db8e4d
--- /dev/null
+++ b/Source/ThirdParty/gtest/codegear/gtest_unittest.cbproj
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{eea63393-5ac5-4b9c-8909-d75fef2daa41}</ProjectGuid>
+ <Config Condition="'$(Config)'==''">Release</Config>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+ <Base>true</Base>
+ <Cfg_1>true</Cfg_1>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+ <Base>true</Base>
+ <Cfg_2>true</Cfg_2>
+ <CfgParent>Base</CfgParent>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Base)'!=''">
+ <OutputExt>exe</OutputExt>
+ <BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
+ <Defines>NO_STRICT</Defines>
+ <DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
+ <DynamicRTL>true</DynamicRTL>
+ <ILINK_ObjectSearchPath>..\test</ILINK_ObjectSearchPath>
+ <UsePackages>true</UsePackages>
+ <ProjectType>CppConsoleApplication</ProjectType>
+ <NoVCL>true</NoVCL>
+ <BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
+ <PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi</PackageImports>
+ <BCC_wpar>false</BCC_wpar>
+ <IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</IncludePath>
+ <ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</ILINK_LibraryPath>
+ <Multithreaded>true</Multithreaded>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
+ <BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
+ <DCC_Optimize>false</DCC_Optimize>
+ <DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
+ <Defines>_DEBUG;$(Defines)</Defines>
+ <ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
+ <BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
+ <ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
+ <BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
+ <DCC_Define>DEBUG</DCC_Define>
+ <BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
+ <IntermediateOutputDir>Debug</IntermediateOutputDir>
+ <TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
+ <BCC_StackFrames>true</BCC_StackFrames>
+ <BCC_DisableOptimizations>true</BCC_DisableOptimizations>
+ <ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>Full</TASM_Debugging>
+ <BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
+ <Defines>NDEBUG;$(Defines)</Defines>
+ <IntermediateOutputDir>Release</IntermediateOutputDir>
+ <ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
+ <TASM_Debugging>None</TASM_Debugging>
+ </PropertyGroup>
+ <ProjectExtensions>
+ <Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
+ <Borland.ProjectType>CppConsoleApplication</Borland.ProjectType>
+ <BorlandProject>
+<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
+
+
+ <Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
+ <Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
+ </Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item1">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item2">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;$(OUTPUTDIR);..\test</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">2</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item1">STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
+ </ProjectExtensions>
+ <Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
+ <ItemGroup>
+ <CppCompile Include="..\test\gtest_unittest.cc">
+ <BuildOrder>0</BuildOrder>
+ </CppCompile>
+ <CppCompile Include="gtest_link.cc">
+ <BuildOrder>1</BuildOrder>
+ </CppCompile>
+ <BuildConfiguration Include="Debug">
+ <Key>Cfg_1</Key>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Release">
+ <Key>Cfg_2</Key>
+ </BuildConfiguration>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Source/ThirdParty/gtest/configure.ac b/Source/ThirdParty/gtest/configure.ac
new file mode 100644
index 000000000..1b9123746
--- /dev/null
+++ b/Source/ThirdParty/gtest/configure.ac
@@ -0,0 +1,67 @@
+m4_include(m4/acx_pthread.m4)
+
+# At this point, the Xcode project assumes the version string will be three
+# integers separated by periods and surrounded by square brackets (e.g.
+# "[1.0.1]"). It also asumes that there won't be any closing parenthesis
+# between "AC_INIT(" and the closing ")" including comments and strings.
+AC_INIT([Google C++ Testing Framework],
+ [1.5.0],
+ [googletestframework@googlegroups.com],
+ [gtest])
+
+# Provide various options to initialize the Autoconf and configure processes.
+AC_PREREQ([2.59])
+AC_CONFIG_SRCDIR([./COPYING])
+AC_CONFIG_AUX_DIR([build-aux])
+AC_CONFIG_HEADERS([build-aux/config.h])
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([scripts/gtest-config], [chmod +x scripts/gtest-config])
+
+# Initialize Automake with various options. We require at least v1.9, prevent
+# pedantic complaints about package files, and enable various distribution
+# targets.
+AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects])
+
+# Check for programs used in building Google Test.
+AC_PROG_CC
+AC_PROG_CXX
+AC_LANG([C++])
+AC_PROG_LIBTOOL
+
+# TODO(chandlerc@google.com): Currently we aren't running the Python tests
+# against the interpreter detected by AM_PATH_PYTHON, and so we condition
+# HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's
+# version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env"
+# hashbang.
+PYTHON= # We *do not* allow the user to specify a python interpreter
+AC_PATH_PROG([PYTHON],[python],[:])
+AS_IF([test "$PYTHON" != ":"],
+ [AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])])
+AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"])
+
+# Configure pthreads.
+AC_ARG_WITH([pthreads],
+ [AS_HELP_STRING([--with-pthreads],
+ [use pthreads (default is yes)])],
+ [with_pthreads=$withval],
+ [with_pthreads=check])
+
+have_pthreads=no
+AS_IF([test "x$with_pthreads" != "xno"],
+ [ACX_PTHREAD(
+ [],
+ [AS_IF([test "x$with_pthreads" != "xcheck"],
+ [AC_MSG_FAILURE(
+ [--with-pthreads was specified, but unable to be used])])])
+ have_pthreads="$acx_pthread_ok"])
+AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" == "xyes"])
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_LIBS)
+
+# TODO(chandlerc@google.com) Check for the necessary system headers.
+
+# TODO(chandlerc@google.com) Check the types, structures, and other compiler
+# and architecture characteristics.
+
+# Output the generated files. No further autoconf macros may be used.
+AC_OUTPUT
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest-death-test.h b/Source/ThirdParty/gtest/include/gtest/gtest-death-test.h
new file mode 100644
index 000000000..121dc1fb5
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest-death-test.h
@@ -0,0 +1,283 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for death tests. It is
+// #included by gtest.h so a user doesn't need to include this
+// directly.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
+
+#include <gtest/internal/gtest-death-test-internal.h>
+
+namespace testing {
+
+// This flag controls the style of death tests. Valid values are "threadsafe",
+// meaning that the death test child process will re-execute the test binary
+// from the start, running only a single death test, or "fast",
+// meaning that the child process will execute the test logic immediately
+// after forking.
+GTEST_DECLARE_string_(death_test_style);
+
+#if GTEST_HAS_DEATH_TEST
+
+// The following macros are useful for writing death tests.
+
+// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
+// executed:
+//
+// 1. It generates a warning if there is more than one active
+// thread. This is because it's safe to fork() or clone() only
+// when there is a single thread.
+//
+// 2. The parent process clone()s a sub-process and runs the death
+// test in it; the sub-process exits with code 0 at the end of the
+// death test, if it hasn't exited already.
+//
+// 3. The parent process waits for the sub-process to terminate.
+//
+// 4. The parent process checks the exit code and error message of
+// the sub-process.
+//
+// Examples:
+//
+// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
+// for (int i = 0; i < 5; i++) {
+// EXPECT_DEATH(server.ProcessRequest(i),
+// "Invalid request .* in ProcessRequest()")
+// << "Failed to die on request " << i);
+// }
+//
+// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
+//
+// bool KilledBySIGHUP(int exit_code) {
+// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
+// }
+//
+// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
+//
+// On the regular expressions used in death tests:
+//
+// On POSIX-compliant systems (*nix), we use the <regex.h> library,
+// which uses the POSIX extended regex syntax.
+//
+// On other platforms (e.g. Windows), we only support a simple regex
+// syntax implemented as part of Google Test. This limited
+// implementation should be enough most of the time when writing
+// death tests; though it lacks many features you can find in PCRE
+// or POSIX extended regex syntax. For example, we don't support
+// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
+// repetition count ("x{5,7}"), among others.
+//
+// Below is the syntax that we do support. We chose it to be a
+// subset of both PCRE and POSIX extended regex, so it's easy to
+// learn wherever you come from. In the following: 'A' denotes a
+// literal character, period (.), or a single \\ escape sequence;
+// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
+// natural numbers.
+//
+// c matches any literal character c
+// \\d matches any decimal digit
+// \\D matches any character that's not a decimal digit
+// \\f matches \f
+// \\n matches \n
+// \\r matches \r
+// \\s matches any ASCII whitespace, including \n
+// \\S matches any character that's not a whitespace
+// \\t matches \t
+// \\v matches \v
+// \\w matches any letter, _, or decimal digit
+// \\W matches any character that \\w doesn't match
+// \\c matches any literal character c, which must be a punctuation
+// . matches any single character except \n
+// A? matches 0 or 1 occurrences of A
+// A* matches 0 or many occurrences of A
+// A+ matches 1 or many occurrences of A
+// ^ matches the beginning of a string (not that of each line)
+// $ matches the end of a string (not that of each line)
+// xy matches x followed by y
+//
+// If you accidentally use PCRE or POSIX extended regex features
+// not implemented by us, you will get a run-time failure. In that
+// case, please try to rewrite your regular expression within the
+// above syntax.
+//
+// This implementation is *not* meant to be as highly tuned or robust
+// as a compiled regex library, but should perform well enough for a
+// death test, which already incurs significant overhead by launching
+// a child process.
+//
+// Known caveats:
+//
+// A "threadsafe" style death test obtains the path to the test
+// program from argv[0] and re-executes it in the sub-process. For
+// simplicity, the current implementation doesn't search the PATH
+// when launching the sub-process. This means that the user must
+// invoke the test program via a path that contains at least one
+// path separator (e.g. path/to/foo_test and
+// /absolute/path/to/bar_test are fine, but foo_test is not). This
+// is rarely a problem as people usually don't put the test binary
+// directory in PATH.
+//
+// TODO(wan@google.com): make thread-safe death tests search the PATH.
+
+// Asserts that a given statement causes the program to exit, with an
+// integer exit status that satisfies predicate, and emitting error output
+// that matches regex.
+#define ASSERT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
+
+// Like ASSERT_EXIT, but continues on to successive tests in the
+// test case, if any:
+#define EXPECT_EXIT(statement, predicate, regex) \
+ GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
+
+// Asserts that a given statement causes the program to exit, either by
+// explicitly exiting with a nonzero exit code or being killed by a
+// signal, and emitting error output that matches regex.
+#define ASSERT_DEATH(statement, regex) \
+ ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Like ASSERT_DEATH, but continues on to successive tests in the
+// test case, if any:
+#define EXPECT_DEATH(statement, regex) \
+ EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
+
+// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
+
+// Tests that an exit code describes a normal exit with a given exit code.
+class GTEST_API_ ExitedWithCode {
+ public:
+ explicit ExitedWithCode(int exit_code);
+ bool operator()(int exit_status) const;
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ExitedWithCode& other);
+
+ const int exit_code_;
+};
+
+#if !GTEST_OS_WINDOWS
+// Tests that an exit code describes an exit due to termination by a
+// given signal.
+class GTEST_API_ KilledBySignal {
+ public:
+ explicit KilledBySignal(int signum);
+ bool operator()(int exit_status) const;
+ private:
+ const int signum_;
+};
+#endif // !GTEST_OS_WINDOWS
+
+// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
+// The death testing framework causes this to have interesting semantics,
+// since the sideeffects of the call are only visible in opt mode, and not
+// in debug mode.
+//
+// In practice, this can be used to test functions that utilize the
+// LOG(DFATAL) macro using the following style:
+//
+// int DieInDebugOr12(int* sideeffect) {
+// if (sideeffect) {
+// *sideeffect = 12;
+// }
+// LOG(DFATAL) << "death";
+// return 12;
+// }
+//
+// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
+// int sideeffect = 0;
+// // Only asserts in dbg.
+// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
+//
+// #ifdef NDEBUG
+// // opt-mode has sideeffect visible.
+// EXPECT_EQ(12, sideeffect);
+// #else
+// // dbg-mode no visible sideeffect.
+// EXPECT_EQ(0, sideeffect);
+// #endif
+// }
+//
+// This will assert that DieInDebugReturn12InOpt() crashes in debug
+// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
+// appropriate fallback value (12 in this case) in opt mode. If you
+// need to test that a function has appropriate side-effects in opt
+// mode, include assertions against the side-effects. A general
+// pattern for this is:
+//
+// EXPECT_DEBUG_DEATH({
+// // Side-effects here will have an effect after this statement in
+// // opt mode, but none in debug mode.
+// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
+// }, "death");
+//
+#ifdef NDEBUG
+
+#define EXPECT_DEBUG_DEATH(statement, regex) \
+ do { statement; } while (::testing::internal::AlwaysFalse())
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+ do { statement; } while (::testing::internal::AlwaysFalse())
+
+#else
+
+#define EXPECT_DEBUG_DEATH(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+
+#define ASSERT_DEBUG_DEATH(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+
+#endif // NDEBUG for EXPECT_DEBUG_DEATH
+#endif // GTEST_HAS_DEATH_TEST
+
+// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
+// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
+// death tests are supported; otherwise they just issue a warning. This is
+// useful when you are combining death test assertions with normal test
+// assertions in one test.
+#if GTEST_HAS_DEATH_TEST
+#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ EXPECT_DEATH(statement, regex)
+#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+ ASSERT_DEATH(statement, regex)
+#else
+#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
+ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
+#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
+ GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
+#endif
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest-message.h b/Source/ThirdParty/gtest/include/gtest/gtest-message.h
new file mode 100644
index 000000000..f135b6942
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest-message.h
@@ -0,0 +1,230 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the Message class.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
+
+#include <limits>
+
+#include <gtest/internal/gtest-string.h>
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+
+// The Message class works like an ostream repeater.
+//
+// Typical usage:
+//
+// 1. You stream a bunch of values to a Message object.
+// It will remember the text in a StrStream.
+// 2. Then you stream the Message object to an ostream.
+// This causes the text in the Message to be streamed
+// to the ostream.
+//
+// For example;
+//
+// testing::Message foo;
+// foo << 1 << " != " << 2;
+// std::cout << foo;
+//
+// will print "1 != 2".
+//
+// Message is not intended to be inherited from. In particular, its
+// destructor is not virtual.
+//
+// Note that StrStream behaves differently in gcc and in MSVC. You
+// can stream a NULL char pointer to it in the former, but not in the
+// latter (it causes an access violation if you do). The Message
+// class hides this difference by treating a NULL char pointer as
+// "(null)".
+class GTEST_API_ Message {
+ private:
+ // The type of basic IO manipulators (endl, ends, and flush) for
+ // narrow streams.
+ typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
+
+ public:
+ // Constructs an empty Message.
+ // We allocate the StrStream separately because it otherwise each use of
+ // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
+ // stack frame leading to huge stack frames in some cases; gcc does not reuse
+ // the stack space.
+ Message() : ss_(new internal::StrStream) {
+ // By default, we want there to be enough precision when printing
+ // a double to a Message.
+ *ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
+ }
+
+ // Copy constructor.
+ Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT
+ *ss_ << msg.GetString();
+ }
+
+ // Constructs a Message from a C-string.
+ explicit Message(const char* str) : ss_(new internal::StrStream) {
+ *ss_ << str;
+ }
+
+ ~Message() { delete ss_; }
+#if GTEST_OS_SYMBIAN
+ // Streams a value (either a pointer or not) to this object.
+ template <typename T>
+ inline Message& operator <<(const T& value) {
+ StreamHelper(typename internal::is_pointer<T>::type(), value);
+ return *this;
+ }
+#else
+ // Streams a non-pointer value to this object.
+ template <typename T>
+ inline Message& operator <<(const T& val) {
+ ::GTestStreamToHelper(ss_, val);
+ return *this;
+ }
+
+ // Streams a pointer value to this object.
+ //
+ // This function is an overload of the previous one. When you
+ // stream a pointer to a Message, this definition will be used as it
+ // is more specialized. (The C++ Standard, section
+ // [temp.func.order].) If you stream a non-pointer, then the
+ // previous definition will be used.
+ //
+ // The reason for this overload is that streaming a NULL pointer to
+ // ostream is undefined behavior. Depending on the compiler, you
+ // may get "0", "(nil)", "(null)", or an access violation. To
+ // ensure consistent result across compilers, we always treat NULL
+ // as "(null)".
+ template <typename T>
+ inline Message& operator <<(T* const& pointer) { // NOLINT
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ ::GTestStreamToHelper(ss_, pointer);
+ }
+ return *this;
+ }
+#endif // GTEST_OS_SYMBIAN
+
+ // Since the basic IO manipulators are overloaded for both narrow
+ // and wide streams, we have to provide this specialized definition
+ // of operator <<, even though its body is the same as the
+ // templatized version above. Without this definition, streaming
+ // endl or other basic IO manipulators to Message will confuse the
+ // compiler.
+ Message& operator <<(BasicNarrowIoManip val) {
+ *ss_ << val;
+ return *this;
+ }
+
+ // Instead of 1/0, we want to see true/false for bool values.
+ Message& operator <<(bool b) {
+ return *this << (b ? "true" : "false");
+ }
+
+ // These two overloads allow streaming a wide C string to a Message
+ // using the UTF-8 encoding.
+ Message& operator <<(const wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+ }
+ Message& operator <<(wchar_t* wide_c_str) {
+ return *this << internal::String::ShowWideCString(wide_c_str);
+ }
+
+#if GTEST_HAS_STD_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::std::wstring& wstr);
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+ // Converts the given wide string to a narrow string using the UTF-8
+ // encoding, and streams the result to this Message object.
+ Message& operator <<(const ::wstring& wstr);
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+ // Gets the text streamed to this object so far as a String.
+ // Each '\0' character in the buffer is replaced with "\\0".
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::String GetString() const {
+ return internal::StrStreamToString(ss_);
+ }
+
+ private:
+#if GTEST_OS_SYMBIAN
+ // These are needed as the Nokia Symbian Compiler cannot decide between
+ // const T& and const T* in a function template. The Nokia compiler _can_
+ // decide between class template specializations for T and T*, so a
+ // tr1::type_traits-like is_pointer works, and we can overload on that.
+ template <typename T>
+ inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) {
+ if (pointer == NULL) {
+ *ss_ << "(null)";
+ } else {
+ ::GTestStreamToHelper(ss_, pointer);
+ }
+ }
+ template <typename T>
+ inline void StreamHelper(internal::false_type /*dummy*/, const T& value) {
+ ::GTestStreamToHelper(ss_, value);
+ }
+#endif // GTEST_OS_SYMBIAN
+
+ // We'll hold the text streamed to this object here.
+ internal::StrStream* const ss_;
+
+ // We declare (but don't implement) this to prevent the compiler
+ // from implementing the assignment operator.
+ void operator=(const Message&);
+};
+
+// Streams a Message to an ostream.
+inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
+ return os << sb.GetString();
+}
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest-param-test.h b/Source/ThirdParty/gtest/include/gtest/gtest-param-test.h
new file mode 100644
index 000000000..810069644
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest-param-test.h
@@ -0,0 +1,1392 @@
+// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl@google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It must be derived from testing::TestWithParam<T>, where T is
+// the type of your parameter values. TestWithParam<T> is itself derived
+// from testing::Test. T can be any copyable type. If it's a raw pointer,
+// you are responsible for managing the lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+ // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+ // Inside a test, access the test parameter with the GetParam() method
+ // of the TestWithParam<T> class:
+ EXPECT_TRUE(foo.Blah(GetParam()));
+ ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+ ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a summary of them, which
+// are all in the testing namespace:
+//
+//
+// Range(begin, end [, step]) - Yields values {begin, begin+step,
+// begin+step+step, ...}. The values do not
+// include end. step defaults to 1.
+// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
+// ValuesIn(container) - Yields values from a C-style array, an STL
+// ValuesIn(begin,end) container, or an iterator range [begin, end).
+// Bool() - Yields sequence {false, true}.
+// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
+// for the math savvy) of the values generated
+// by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+// * InstantiationName/FooTest.DoesBlah/1 for "miny"
+// * InstantiationName/FooTest.DoesBlah/2 for "moe"
+// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions (including parameters to the
+// generators) are evaluated in InitGoogleTest(), after main() has started.
+// This allows the user on one hand, to adjust generator parameters in order
+// to dynamically determine a set of tests to run and on the other hand,
+// give the user a chance to inspect the generated tests with Google Test
+// reflection API before RUN_ALL_TESTS() is executed.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+
+#endif // 0
+
+#include <gtest/internal/gtest-port.h>
+
+#if !GTEST_OS_SYMBIAN
+#include <utility>
+#endif
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-param-util.h>
+#include <gtest/internal/gtest-param-util-generated.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+// - returns a generator producing a sequence of values {start, start+1,
+// start+2, ..., }.
+// Range(start, end, step)
+// - returns a generator producing a sequence of values {start, start+step,
+// start+step+step, ..., }.
+// Notes:
+// * The generated sequences never include end. For example, Range(1, 5)
+// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+// returns a generator producing {1, 3, 5, 7}.
+// * start and end must have the same type. That type may be any integral or
+// floating-point type or a user defined type satisfying these conditions:
+// * It must be assignable (have operator=() defined).
+// * It must have operator+() (operator+(int-compatible type) for
+// two-operand version).
+// * It must have operator<() defined.
+// Elements in the resulting sequences will also have that type.
+// * Condition start < end must be satisfied in order for resulting sequences
+// to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+ return internal::ParamGenerator<T>(
+ new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+ return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+// - returns a generator producing sequences with elements from
+// a C-style array.
+// ValuesIn(const Container& container)
+// - returns a generator producing sequences with elements from
+// an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+// - returns a generator producing sequences with elements from
+// a range [begin, end) defined by a pair of STL-style iterators. These
+// iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+// ::std::vector< ::std::string> v;
+// v.push_back("a");
+// v.push_back("b");
+// return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+// ::std::list<char> list;
+// list.push_back('a');
+// list.push_back('b');
+// return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(
+ ForwardIterator begin,
+ ForwardIterator end) {
+ typedef typename ::std::iterator_traits<ForwardIterator>::value_type
+ ParamType;
+ return internal::ParamGenerator<ParamType>(
+ new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+ return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container) {
+ return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+// - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to 50 parameters.
+//
+template <typename T1>
+internal::ValueArray1<T1> Values(T1 v1) {
+ return internal::ValueArray1<T1>(v1);
+}
+
+template <typename T1, typename T2>
+internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
+ return internal::ValueArray2<T1, T2>(v1, v2);
+}
+
+template <typename T1, typename T2, typename T3>
+internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
+ return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
+ return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5) {
+ return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6) {
+ return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7) {
+ return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
+ v6, v7);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
+ return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
+ v5, v6, v7, v8);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
+ return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
+ return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+ T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11) {
+ return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
+ T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12) {
+ return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13) {
+ return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
+ return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
+ return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16) {
+ return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17) {
+ return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18) {
+ return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
+ return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
+ return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
+ return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22) {
+ return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23) {
+ return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24) {
+ return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
+ v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+ v19, v20, v21, v22, v23, v24);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+ T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+ T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
+ return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+ v18, v19, v20, v21, v22, v23, v24, v25);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26) {
+ return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27) {
+ return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+ v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28) {
+ return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+ v28);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29) {
+ return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+ v27, v28, v29);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
+ return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+ v26, v27, v28, v29, v30);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
+ return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+ v25, v26, v27, v28, v29, v30, v31);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32) {
+ return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33) {
+ return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+ T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+ T31 v31, T32 v32, T33 v33, T34 v34) {
+ return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+ v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
+ return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+ v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
+ return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
+ T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37) {
+ return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
+ v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36, v37);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37, T38 v38) {
+ return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
+ v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
+ v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
+ v33, v34, v35, v36, v37, v38);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
+ T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
+ T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
+ T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
+ T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
+ T37 v37, T38 v38, T39 v39) {
+ return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
+ v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
+ v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
+ v32, v33, v34, v35, v36, v37, v38, v39);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
+ T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
+ T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
+ T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
+ T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
+ T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
+ return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
+ v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
+ v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
+ return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
+ v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
+ v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42) {
+ return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
+ v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
+ v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
+ v42);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43) {
+ return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
+ v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
+ v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+ v41, v42, v43);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44) {
+ return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
+ v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
+ v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
+ v40, v41, v42, v43, v44);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+ T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+ T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
+ return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+ v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
+ v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
+ v39, v40, v41, v42, v43, v44, v45);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
+ return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
+ v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+ v38, v39, v40, v41, v42, v43, v44, v45, v46);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
+ return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
+ v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
+ v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
+ v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
+ T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
+ T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
+ T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
+ T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
+ T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
+ T48 v48) {
+ return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
+ v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
+ v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
+ v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
+ T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
+ T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
+ T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
+ T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
+ T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
+ T47 v47, T48 v48, T49 v49) {
+ return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
+ v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
+ v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
+ v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
+ T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
+ T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
+ T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
+ T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
+ T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
+ T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
+ return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
+ v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
+ v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
+ v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
+ v48, v49, v50);
+}
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+// - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+// virtual void SetUp() {
+// external_flag = GetParam();
+// }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+ return Values(false, true);
+}
+
+#if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+// - returns a generator producing sequences with elements coming from
+// the Cartesian product of elements from the sequences generated by
+// gen1, gen2, ..., genN. The sequence elements will have a type of
+// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to 10 arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+// : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+// Combine(Values("cat", "dog"),
+// Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+// : public testing::TestWithParam<tuple(bool, bool)> > {
+// virtual void SetUp() {
+// // Assigns external_flag_1 and external_flag_2 values from the tuple.
+// tie(external_flag_1, external_flag_2) = GetParam();
+// }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+// // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+template <typename Generator1, typename Generator2>
+internal::CartesianProductHolder2<Generator1, Generator2> Combine(
+ const Generator1& g1, const Generator2& g2) {
+ return internal::CartesianProductHolder2<Generator1, Generator2>(
+ g1, g2);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3>
+internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3) {
+ return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
+ g1, g2, g3);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4>
+internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+ Generator4> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4) {
+ return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
+ Generator4>(
+ g1, g2, g3, g4);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5>
+internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+ Generator4, Generator5> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5) {
+ return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
+ Generator4, Generator5>(
+ g1, g2, g3, g4, g5);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6>
+internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6) {
+ return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6>(
+ g1, g2, g3, g4, g5, g6);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7>
+internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7) {
+ return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7>(
+ g1, g2, g3, g4, g5, g6, g7);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8>
+internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8) {
+ return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8>(
+ g1, g2, g3, g4, g5, g6, g7, g8);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8, typename Generator9>
+internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8,
+ Generator9> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8, const Generator9& g9) {
+ return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
+ g1, g2, g3, g4, g5, g6, g7, g8, g9);
+}
+
+template <typename Generator1, typename Generator2, typename Generator3,
+ typename Generator4, typename Generator5, typename Generator6,
+ typename Generator7, typename Generator8, typename Generator9,
+ typename Generator10>
+internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+ Generator10> Combine(
+ const Generator1& g1, const Generator2& g2, const Generator3& g3,
+ const Generator4& g4, const Generator5& g5, const Generator6& g6,
+ const Generator7& g7, const Generator8& g8, const Generator9& g9,
+ const Generator10& g10) {
+ return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
+ Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
+ Generator10>(
+ g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
+}
+#endif // GTEST_HAS_COMBINE
+
+
+
+#define TEST_P(test_case_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ : public test_case_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+ virtual void TestBody(); \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+ #test_case_name, \
+ #test_name, \
+ new ::testing::internal::TestMetaFactory< \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_case_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+ ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+ int gtest_##prefix##test_case_name##_dummy_ = \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+ #prefix, \
+ &gtest_##prefix##test_case_name##_EvalGenerator_, \
+ __FILE__, __LINE__)
+
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest-param-test.h.pump b/Source/ThirdParty/gtest/include/gtest/gtest-param-test.h.pump
new file mode 100644
index 000000000..a23118827
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest-param-test.h.pump
@@ -0,0 +1,457 @@
+$$ -*- mode: c++; -*-
+$var n = 50 $$ Maximum length of Values arguments we want to support.
+$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl@google.com (Vlad Losev)
+//
+// Macros and functions for implementing parameterized tests
+// in Google C++ Testing Framework (Google Test)
+//
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
+
+
+// Value-parameterized tests allow you to test your code with different
+// parameters without writing multiple copies of the same test.
+//
+// Here is how you use value-parameterized tests:
+
+#if 0
+
+// To write value-parameterized tests, first you should define a fixture
+// class. It must be derived from testing::TestWithParam<T>, where T is
+// the type of your parameter values. TestWithParam<T> is itself derived
+// from testing::Test. T can be any copyable type. If it's a raw pointer,
+// you are responsible for managing the lifespan of the pointed values.
+
+class FooTest : public ::testing::TestWithParam<const char*> {
+ // You can implement all the usual class fixture members here.
+};
+
+// Then, use the TEST_P macro to define as many parameterized tests
+// for this fixture as you want. The _P suffix is for "parameterized"
+// or "pattern", whichever you prefer to think.
+
+TEST_P(FooTest, DoesBlah) {
+ // Inside a test, access the test parameter with the GetParam() method
+ // of the TestWithParam<T> class:
+ EXPECT_TRUE(foo.Blah(GetParam()));
+ ...
+}
+
+TEST_P(FooTest, HasBlahBlah) {
+ ...
+}
+
+// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
+// case with any set of parameters you want. Google Test defines a number
+// of functions for generating test parameters. They return what we call
+// (surprise!) parameter generators. Here is a summary of them, which
+// are all in the testing namespace:
+//
+//
+// Range(begin, end [, step]) - Yields values {begin, begin+step,
+// begin+step+step, ...}. The values do not
+// include end. step defaults to 1.
+// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
+// ValuesIn(container) - Yields values from a C-style array, an STL
+// ValuesIn(begin,end) container, or an iterator range [begin, end).
+// Bool() - Yields sequence {false, true}.
+// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
+// for the math savvy) of the values generated
+// by the N generators.
+//
+// For more details, see comments at the definitions of these functions below
+// in this file.
+//
+// The following statement will instantiate tests from the FooTest test case
+// each with parameter values "meeny", "miny", and "moe".
+
+INSTANTIATE_TEST_CASE_P(InstantiationName,
+ FooTest,
+ Values("meeny", "miny", "moe"));
+
+// To distinguish different instances of the pattern, (yes, you
+// can instantiate it more then once) the first argument to the
+// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
+// actual test case name. Remember to pick unique prefixes for different
+// instantiations. The tests from the instantiation above will have
+// these names:
+//
+// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
+// * InstantiationName/FooTest.DoesBlah/1 for "miny"
+// * InstantiationName/FooTest.DoesBlah/2 for "moe"
+// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
+// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
+// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
+//
+// You can use these names in --gtest_filter.
+//
+// This statement will instantiate all tests from FooTest again, each
+// with parameter values "cat" and "dog":
+
+const char* pets[] = {"cat", "dog"};
+INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
+
+// The tests from the instantiation above will have these names:
+//
+// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
+// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
+//
+// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
+// in the given test case, whether their definitions come before or
+// AFTER the INSTANTIATE_TEST_CASE_P statement.
+//
+// Please also note that generator expressions are evaluated in
+// RUN_ALL_TESTS(), after main() has started. This allows evaluation of
+// parameter list based on command line parameters.
+//
+// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
+// for more examples.
+//
+// In the future, we plan to publish the API for defining new parameter
+// generators. But for now this interface remains part of the internal
+// implementation and is subject to change.
+
+#endif // 0
+
+#include <gtest/internal/gtest-port.h>
+
+#if !GTEST_OS_SYMBIAN
+#include <utility>
+#endif
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-param-util.h>
+#include <gtest/internal/gtest-param-util-generated.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Functions producing parameter generators.
+//
+// Google Test uses these generators to produce parameters for value-
+// parameterized tests. When a parameterized test case is instantiated
+// with a particular generator, Google Test creates and runs tests
+// for each element in the sequence produced by the generator.
+//
+// In the following sample, tests from test case FooTest are instantiated
+// each three times with parameter values 3, 5, and 8:
+//
+// class FooTest : public TestWithParam<int> { ... };
+//
+// TEST_P(FooTest, TestThis) {
+// }
+// TEST_P(FooTest, TestThat) {
+// }
+// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
+//
+
+// Range() returns generators providing sequences of values in a range.
+//
+// Synopsis:
+// Range(start, end)
+// - returns a generator producing a sequence of values {start, start+1,
+// start+2, ..., }.
+// Range(start, end, step)
+// - returns a generator producing a sequence of values {start, start+step,
+// start+step+step, ..., }.
+// Notes:
+// * The generated sequences never include end. For example, Range(1, 5)
+// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
+// returns a generator producing {1, 3, 5, 7}.
+// * start and end must have the same type. That type may be any integral or
+// floating-point type or a user defined type satisfying these conditions:
+// * It must be assignable (have operator=() defined).
+// * It must have operator+() (operator+(int-compatible type) for
+// two-operand version).
+// * It must have operator<() defined.
+// Elements in the resulting sequences will also have that type.
+// * Condition start < end must be satisfied in order for resulting sequences
+// to contain any elements.
+//
+template <typename T, typename IncrementT>
+internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
+ return internal::ParamGenerator<T>(
+ new internal::RangeGenerator<T, IncrementT>(start, end, step));
+}
+
+template <typename T>
+internal::ParamGenerator<T> Range(T start, T end) {
+ return Range(start, end, 1);
+}
+
+// ValuesIn() function allows generation of tests with parameters coming from
+// a container.
+//
+// Synopsis:
+// ValuesIn(const T (&array)[N])
+// - returns a generator producing sequences with elements from
+// a C-style array.
+// ValuesIn(const Container& container)
+// - returns a generator producing sequences with elements from
+// an STL-style container.
+// ValuesIn(Iterator begin, Iterator end)
+// - returns a generator producing sequences with elements from
+// a range [begin, end) defined by a pair of STL-style iterators. These
+// iterators can also be plain C pointers.
+//
+// Please note that ValuesIn copies the values from the containers
+// passed in and keeps them to generate tests in RUN_ALL_TESTS().
+//
+// Examples:
+//
+// This instantiates tests from test case StringTest
+// each with C-string values of "foo", "bar", and "baz":
+//
+// const char* strings[] = {"foo", "bar", "baz"};
+// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
+//
+// This instantiates tests from test case StlStringTest
+// each with STL strings with values "a" and "b":
+//
+// ::std::vector< ::std::string> GetParameterStrings() {
+// ::std::vector< ::std::string> v;
+// v.push_back("a");
+// v.push_back("b");
+// return v;
+// }
+//
+// INSTANTIATE_TEST_CASE_P(CharSequence,
+// StlStringTest,
+// ValuesIn(GetParameterStrings()));
+//
+//
+// This will also instantiate tests from CharTest
+// each with parameter values 'a' and 'b':
+//
+// ::std::list<char> GetParameterChars() {
+// ::std::list<char> list;
+// list.push_back('a');
+// list.push_back('b');
+// return list;
+// }
+// ::std::list<char> l = GetParameterChars();
+// INSTANTIATE_TEST_CASE_P(CharSequence2,
+// CharTest,
+// ValuesIn(l.begin(), l.end()));
+//
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(
+ ForwardIterator begin,
+ ForwardIterator end) {
+ typedef typename ::std::iterator_traits<ForwardIterator>::value_type
+ ParamType;
+ return internal::ParamGenerator<ParamType>(
+ new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
+}
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
+ return ValuesIn(array, array + N);
+}
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container) {
+ return ValuesIn(container.begin(), container.end());
+}
+
+// Values() allows generating tests from explicitly specified list of
+// parameters.
+//
+// Synopsis:
+// Values(T v1, T v2, ..., T vN)
+// - returns a generator producing sequences with elements v1, v2, ..., vN.
+//
+// For example, this instantiates tests from test case BarTest each
+// with values "one", "two", and "three":
+//
+// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
+//
+// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
+// The exact type of values will depend on the type of parameter in BazTest.
+//
+// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
+//
+// Currently, Values() supports from 1 to $n parameters.
+//
+$range i 1..n
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename T$j]]>
+internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) {
+ return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]);
+}
+
+]]
+
+// Bool() allows generating tests with parameters in a set of (false, true).
+//
+// Synopsis:
+// Bool()
+// - returns a generator producing sequences with elements {false, true}.
+//
+// It is useful when testing code that depends on Boolean flags. Combinations
+// of multiple flags can be tested when several Bool()'s are combined using
+// Combine() function.
+//
+// In the following example all tests in the test case FlagDependentTest
+// will be instantiated twice with parameters false and true.
+//
+// class FlagDependentTest : public testing::TestWithParam<bool> {
+// virtual void SetUp() {
+// external_flag = GetParam();
+// }
+// }
+// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
+//
+inline internal::ParamGenerator<bool> Bool() {
+ return Values(false, true);
+}
+
+#if GTEST_HAS_COMBINE
+// Combine() allows the user to combine two or more sequences to produce
+// values of a Cartesian product of those sequences' elements.
+//
+// Synopsis:
+// Combine(gen1, gen2, ..., genN)
+// - returns a generator producing sequences with elements coming from
+// the Cartesian product of elements from the sequences generated by
+// gen1, gen2, ..., genN. The sequence elements will have a type of
+// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
+// of elements from sequences produces by gen1, gen2, ..., genN.
+//
+// Combine can have up to $maxtuple arguments. This number is currently limited
+// by the maximum number of elements in the tuple implementation used by Google
+// Test.
+//
+// Example:
+//
+// This will instantiate tests in test case AnimalTest each one with
+// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
+// tuple("dog", BLACK), and tuple("dog", WHITE):
+//
+// enum Color { BLACK, GRAY, WHITE };
+// class AnimalTest
+// : public testing::TestWithParam<tuple<const char*, Color> > {...};
+//
+// TEST_P(AnimalTest, AnimalLooksNice) {...}
+//
+// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
+// Combine(Values("cat", "dog"),
+// Values(BLACK, WHITE)));
+//
+// This will instantiate tests in FlagDependentTest with all variations of two
+// Boolean flags:
+//
+// class FlagDependentTest
+// : public testing::TestWithParam<tuple(bool, bool)> > {
+// virtual void SetUp() {
+// // Assigns external_flag_1 and external_flag_2 values from the tuple.
+// tie(external_flag_1, external_flag_2) = GetParam();
+// }
+// };
+//
+// TEST_P(FlagDependentTest, TestFeature1) {
+// // Test your code using external_flag_1 and external_flag_2 here.
+// }
+// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
+// Combine(Bool(), Bool()));
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename Generator$j]]>
+internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine(
+ $for j, [[const Generator$j& g$j]]) {
+ return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>(
+ $for j, [[g$j]]);
+}
+
+]]
+#endif // GTEST_HAS_COMBINE
+
+
+
+#define TEST_P(test_case_name, test_name) \
+ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ : public test_case_name { \
+ public: \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
+ virtual void TestBody(); \
+ private: \
+ static int AddToRegistry() { \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
+ #test_case_name, \
+ #test_name, \
+ new ::testing::internal::TestMetaFactory< \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+ return 0; \
+ } \
+ static int gtest_registering_dummy_; \
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
+ }; \
+ int GTEST_TEST_CLASS_NAME_(test_case_name, \
+ test_name)::gtest_registering_dummy_ = \
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
+ void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+ ::testing::internal::ParamGenerator<test_case_name::ParamType> \
+ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
+ int gtest_##prefix##test_case_name##_dummy_ = \
+ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
+ GetTestCasePatternHolder<test_case_name>(\
+ #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
+ #prefix, \
+ &gtest_##prefix##test_case_name##_EvalGenerator_, \
+ __FILE__, __LINE__)
+
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest-spi.h b/Source/ThirdParty/gtest/include/gtest/gtest-spi.h
new file mode 100644
index 000000000..c41da4844
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest-spi.h
@@ -0,0 +1,232 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Utilities for testing Google Test itself and code that uses Google Test
+// (e.g. frameworks built on top of Google Test).
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
+
+#include <gtest/gtest.h>
+
+namespace testing {
+
+// This helper class can be used to mock out Google Test failure reporting
+// so that we can test Google Test or code that builds on Google Test.
+//
+// An object of this class appends a TestPartResult object to the
+// TestPartResultArray object given in the constructor whenever a Google Test
+// failure is reported. It can either intercept only failures that are
+// generated in the same thread that created this object or it can intercept
+// all generated failures. The scope of this mock object can be controlled with
+// the second argument to the two arguments constructor.
+class GTEST_API_ ScopedFakeTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ // The two possible mocking modes of this object.
+ enum InterceptMode {
+ INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
+ INTERCEPT_ALL_THREADS // Intercepts all failures.
+ };
+
+ // The c'tor sets this object as the test part result reporter used
+ // by Google Test. The 'result' parameter specifies where to report the
+ // results. This reporter will only catch failures generated in the current
+ // thread. DEPRECATED
+ explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
+
+ // Same as above, but you can choose the interception scope of this object.
+ ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
+ TestPartResultArray* result);
+
+ // The d'tor restores the previous test part result reporter.
+ virtual ~ScopedFakeTestPartResultReporter();
+
+ // Appends the TestPartResult object to the TestPartResultArray
+ // received in the constructor.
+ //
+ // This method is from the TestPartResultReporterInterface
+ // interface.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ private:
+ void Init();
+
+ const InterceptMode intercept_mode_;
+ TestPartResultReporterInterface* old_reporter_;
+ TestPartResultArray* const result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
+};
+
+namespace internal {
+
+// A helper class for implementing EXPECT_FATAL_FAILURE() and
+// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+class GTEST_API_ SingleFailureChecker {
+ public:
+ // The constructor remembers the arguments.
+ SingleFailureChecker(const TestPartResultArray* results,
+ TestPartResult::Type type,
+ const char* substr);
+ ~SingleFailureChecker();
+ private:
+ const TestPartResultArray* const results_;
+ const TestPartResult::Type type_;
+ const String substr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+// A set of macros for testing Google Test assertions or code that's expected
+// to generate Google Test fatal failures. It verifies that the given
+// statement will cause exactly one fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - 'statement' cannot reference local non-static variables or
+// non-static members of the current object.
+// - 'statement' cannot return a value.
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
+// gtest_unittest.cc will fail to compile if we do that.
+#define EXPECT_FATAL_FAILURE(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do { \
+ class GTestExpectFatalFailureHelper {\
+ public:\
+ static void Execute() { statement; }\
+ };\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ALL_THREADS, &gtest_failures);\
+ GTestExpectFatalFailureHelper::Execute();\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+// A macro for testing Google Test assertions or code that's expected to
+// generate Google Test non-fatal failures. It asserts that the given
+// statement will cause exactly one non-fatal Google Test failure with 'substr'
+// being part of the failure message.
+//
+// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
+// affects and considers failures generated in the current thread and
+// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
+//
+// 'statement' is allowed to reference local variables and members of
+// the current object.
+//
+// The verification of the assertion is done correctly even when the statement
+// throws an exception or aborts the current function.
+//
+// Known restrictions:
+// - You cannot stream a failure message to this macro.
+//
+// Note that even though the implementations of the following two
+// macros are much alike, we cannot refactor them to use a common
+// helper macro, due to some peculiarity in how the preprocessor
+// works. If we do that, the code won't compile when the user gives
+// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
+// expands to code containing an unprotected comma. The
+// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
+// catches that.
+//
+// For the same reason, we have to write
+// if (::testing::internal::AlwaysTrue()) { statement; }
+// instead of
+// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
+// to avoid an MSVC warning on unreachable code.
+#define EXPECT_NONFATAL_FAILURE(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter:: \
+ INTERCEPT_ONLY_CURRENT_THREAD, &gtest_failures);\
+ if (::testing::internal::AlwaysTrue()) { statement; }\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
+ do {\
+ ::testing::TestPartResultArray gtest_failures;\
+ ::testing::internal::SingleFailureChecker gtest_checker(\
+ &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
+ (substr));\
+ {\
+ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
+ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
+ &gtest_failures);\
+ if (::testing::internal::AlwaysTrue()) { statement; }\
+ }\
+ } while (::testing::internal::AlwaysFalse())
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest-test-part.h b/Source/ThirdParty/gtest/include/gtest/gtest-test-part.h
new file mode 100644
index 000000000..f71475906
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest-test-part.h
@@ -0,0 +1,176 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
+
+#include <iosfwd>
+#include <vector>
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+
+// A copyable object representing the result of a test part (i.e. an
+// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
+//
+// Don't inherit from TestPartResult as its destructor is not virtual.
+class GTEST_API_ TestPartResult {
+ public:
+ // The possible outcomes of a test part (i.e. an assertion or an
+ // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
+ enum Type {
+ kSuccess, // Succeeded.
+ kNonFatalFailure, // Failed but the test can continue.
+ kFatalFailure // Failed and the test should be terminated.
+ };
+
+ // C'tor. TestPartResult does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestPartResult object.
+ TestPartResult(Type a_type,
+ const char* a_file_name,
+ int a_line_number,
+ const char* a_message)
+ : type_(a_type),
+ file_name_(a_file_name),
+ line_number_(a_line_number),
+ summary_(ExtractSummary(a_message)),
+ message_(a_message) {
+ }
+
+ // Gets the outcome of the test part.
+ Type type() const { return type_; }
+
+ // Gets the name of the source file where the test part took place, or
+ // NULL if it's unknown.
+ const char* file_name() const { return file_name_.c_str(); }
+
+ // Gets the line in the source file where the test part took place,
+ // or -1 if it's unknown.
+ int line_number() const { return line_number_; }
+
+ // Gets the summary of the failure message.
+ const char* summary() const { return summary_.c_str(); }
+
+ // Gets the message associated with the test part.
+ const char* message() const { return message_.c_str(); }
+
+ // Returns true iff the test part passed.
+ bool passed() const { return type_ == kSuccess; }
+
+ // Returns true iff the test part failed.
+ bool failed() const { return type_ != kSuccess; }
+
+ // Returns true iff the test part non-fatally failed.
+ bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
+
+ // Returns true iff the test part fatally failed.
+ bool fatally_failed() const { return type_ == kFatalFailure; }
+ private:
+ Type type_;
+
+ // Gets the summary of the failure message by omitting the stack
+ // trace in it.
+ static internal::String ExtractSummary(const char* message);
+
+ // The name of the source file where the test part took place, or
+ // NULL if the source file is unknown.
+ internal::String file_name_;
+ // The line in the source file where the test part took place, or -1
+ // if the line number is unknown.
+ int line_number_;
+ internal::String summary_; // The test failure summary.
+ internal::String message_; // The test failure message.
+};
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
+
+// An array of TestPartResult objects.
+//
+// Don't inherit from TestPartResultArray as its destructor is not
+// virtual.
+class GTEST_API_ TestPartResultArray {
+ public:
+ TestPartResultArray() {}
+
+ // Appends the given TestPartResult to the array.
+ void Append(const TestPartResult& result);
+
+ // Returns the TestPartResult at the given index (0-based).
+ const TestPartResult& GetTestPartResult(int index) const;
+
+ // Returns the number of TestPartResult objects in the array.
+ int size() const;
+
+ private:
+ std::vector<TestPartResult> array_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
+};
+
+// This interface knows how to report a test part result.
+class TestPartResultReporterInterface {
+ public:
+ virtual ~TestPartResultReporterInterface() {}
+
+ virtual void ReportTestPartResult(const TestPartResult& result) = 0;
+};
+
+namespace internal {
+
+// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
+// statement generates new fatal failures. To do so it registers itself as the
+// current test part result reporter. Besides checking if fatal failures were
+// reported, it only delegates the reporting to the former result reporter.
+// The original result reporter is restored in the destructor.
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+class GTEST_API_ HasNewFatalFailureHelper
+ : public TestPartResultReporterInterface {
+ public:
+ HasNewFatalFailureHelper();
+ virtual ~HasNewFatalFailureHelper();
+ virtual void ReportTestPartResult(const TestPartResult& result);
+ bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
+ private:
+ bool has_new_fatal_failure_;
+ TestPartResultReporterInterface* original_reporter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
+};
+
+} // namespace internal
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest-typed-test.h b/Source/ThirdParty/gtest/include/gtest/gtest-typed-test.h
new file mode 100644
index 000000000..1ec8eb8d3
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest-typed-test.h
@@ -0,0 +1,259 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
+
+// This header implements typed tests and type-parameterized tests.
+
+// Typed (aka type-driven) tests repeat the same test for types in a
+// list. You must know which types you want to test with when writing
+// typed tests. Here's how you do it:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ public:
+ ...
+ typedef std::list<T> List;
+ static T shared_;
+ T value_;
+};
+
+// Next, associate a list of types with the test case, which will be
+// repeated for each type in the list. The typedef is necessary for
+// the macro to parse correctly.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+TYPED_TEST_CASE(FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// TYPED_TEST_CASE(FooTest, int);
+
+// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
+// tests for this test case as you want.
+TYPED_TEST(FooTest, DoesBlah) {
+ // Inside a test, refer to TypeParam to get the type parameter.
+ // Since we are inside a derived class template, C++ requires use to
+ // visit the members of FooTest via 'this'.
+ TypeParam n = this->value_;
+
+ // To visit static members of the fixture, add the TestFixture::
+ // prefix.
+ n += TestFixture::shared_;
+
+ // To refer to typedefs in the fixture, add the "typename
+ // TestFixture::" prefix.
+ typename TestFixture::List values;
+ values.push_back(n);
+ ...
+}
+
+TYPED_TEST(FooTest, HasPropertyA) { ... }
+
+#endif // 0
+
+// Type-parameterized tests are abstract test patterns parameterized
+// by a type. Compared with typed tests, type-parameterized tests
+// allow you to define the test pattern without knowing what the type
+// parameters are. The defined pattern can be instantiated with
+// different types any number of times, in any number of translation
+// units.
+//
+// If you are designing an interface or concept, you can define a
+// suite of type-parameterized tests to verify properties that any
+// valid implementation of the interface/concept should have. Then,
+// each implementation can easily instantiate the test suite to verify
+// that it conforms to the requirements, without having to write
+// similar tests repeatedly. Here's an example:
+
+#if 0
+
+// First, define a fixture class template. It should be parameterized
+// by a type. Remember to derive it from testing::Test.
+template <typename T>
+class FooTest : public testing::Test {
+ ...
+};
+
+// Next, declare that you will define a type-parameterized test case
+// (the _P suffix is for "parameterized" or "pattern", whichever you
+// prefer):
+TYPED_TEST_CASE_P(FooTest);
+
+// Then, use TYPED_TEST_P() to define as many type-parameterized tests
+// for this type-parameterized test case as you want.
+TYPED_TEST_P(FooTest, DoesBlah) {
+ // Inside a test, refer to TypeParam to get the type parameter.
+ TypeParam n = 0;
+ ...
+}
+
+TYPED_TEST_P(FooTest, HasPropertyA) { ... }
+
+// Now the tricky part: you need to register all test patterns before
+// you can instantiate them. The first argument of the macro is the
+// test case name; the rest are the names of the tests in this test
+// case.
+REGISTER_TYPED_TEST_CASE_P(FooTest,
+ DoesBlah, HasPropertyA);
+
+// Finally, you are free to instantiate the pattern with the types you
+// want. If you put the above code in a header file, you can #include
+// it in multiple C++ source files and instantiate it multiple times.
+//
+// To distinguish different instances of the pattern, the first
+// argument to the INSTANTIATE_* macro is a prefix that will be added
+// to the actual test case name. Remember to pick unique prefixes for
+// different instances.
+typedef testing::Types<char, int, unsigned int> MyTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
+
+// If the type list contains only one type, you can write that type
+// directly without Types<...>:
+// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
+
+#endif // 0
+
+#include <gtest/internal/gtest-port.h>
+#include <gtest/internal/gtest-type-util.h>
+
+// Implements typed tests.
+
+#if GTEST_HAS_TYPED_TEST
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the typedef for the type parameters of the
+// given test case.
+#define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+#define TYPED_TEST_CASE(CaseName, Types) \
+ typedef ::testing::internal::TypeList< Types >::type \
+ GTEST_TYPE_PARAMS_(CaseName)
+
+#define TYPED_TEST(CaseName, TestName) \
+ template <typename gtest_TypeParam_> \
+ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
+ : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ bool gtest_##CaseName##_##TestName##_registered_ = \
+ ::testing::internal::TypeParameterizedTest< \
+ CaseName, \
+ ::testing::internal::TemplateSel< \
+ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
+ GTEST_TYPE_PARAMS_(CaseName)>::Register(\
+ "", #CaseName, #TestName, 0); \
+ template <typename gtest_TypeParam_> \
+ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// Implements type-parameterized tests.
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the namespace name that the type-parameterized tests for
+// the given type-parameterized test case are defined in. The exact
+// name of the namespace is subject to change without notice.
+#define GTEST_CASE_NAMESPACE_(TestCaseName) \
+ gtest_case_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Expands to the name of the variable used to remember the names of
+// the defined tests in the given test case.
+#define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
+ gtest_typed_test_case_p_state_##TestCaseName##_
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
+//
+// Expands to the name of the variable used to remember the names of
+// the registered tests in the given test case.
+#define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
+ gtest_registered_test_names_##TestCaseName##_
+
+// The variables defined in the type-parameterized test macros are
+// static as typically these macros are used in a .h file that can be
+// #included in multiple translation units linked together.
+#define TYPED_TEST_CASE_P(CaseName) \
+ static ::testing::internal::TypedTestCasePState \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
+
+#define TYPED_TEST_P(CaseName, TestName) \
+ namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+ template <typename gtest_TypeParam_> \
+ class TestName : public CaseName<gtest_TypeParam_> { \
+ private: \
+ typedef CaseName<gtest_TypeParam_> TestFixture; \
+ typedef gtest_TypeParam_ TypeParam; \
+ virtual void TestBody(); \
+ }; \
+ static bool gtest_##TestName##_defined_ = \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
+ __FILE__, __LINE__, #CaseName, #TestName); \
+ } \
+ template <typename gtest_TypeParam_> \
+ void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
+
+#define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
+ namespace GTEST_CASE_NAMESPACE_(CaseName) { \
+ typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
+ } \
+ static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
+ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
+ __FILE__, __LINE__, #__VA_ARGS__)
+
+// The 'Types' template argument below must have spaces around it
+// since some compilers may choke on '>>' when passing a template
+// instance (e.g. Types<int>)
+#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
+ bool gtest_##Prefix##_##CaseName = \
+ ::testing::internal::TypeParameterizedTestCase<CaseName, \
+ GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
+ ::testing::internal::TypeList< Types >::type>::Register(\
+ #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest.h b/Source/ThirdParty/gtest/include/gtest/gtest.h
new file mode 100644
index 000000000..921fad11f
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest.h
@@ -0,0 +1,2052 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the public API for Google Test. It should be
+// included by any test program that uses Google Test.
+//
+// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
+// leave some internal implementation details in this header file.
+// They are clearly marked by comments like this:
+//
+// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+//
+// Such code is NOT meant to be used by a user directly, and is subject
+// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
+// program!
+//
+// Acknowledgment: Google Test borrowed the idea of automatic test
+// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
+// easyUnit framework.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#define GTEST_INCLUDE_GTEST_GTEST_H_
+
+#include <limits>
+#include <vector>
+
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-string.h>
+#include <gtest/gtest-death-test.h>
+#include <gtest/gtest-message.h>
+#include <gtest/gtest-param-test.h>
+#include <gtest/gtest_prod.h>
+#include <gtest/gtest-test-part.h>
+#include <gtest/gtest-typed-test.h>
+
+// Depending on the platform, different string classes are available.
+// On Linux, in addition to ::std::string, Google also makes use of
+// class ::string, which has the same interface as ::std::string, but
+// has a different implementation.
+//
+// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
+// ::string is available AND is a distinct type to ::std::string, or
+// define it to 0 to indicate otherwise.
+//
+// If the user's ::std::string and ::string are the same class due to
+// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
+//
+// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
+// heuristically.
+
+namespace testing {
+
+// Declares the flags.
+
+// This flag temporary enables the disabled tests.
+GTEST_DECLARE_bool_(also_run_disabled_tests);
+
+// This flag brings the debugger on an assertion failure.
+GTEST_DECLARE_bool_(break_on_failure);
+
+// This flag controls whether Google Test catches all test-thrown exceptions
+// and logs them as failures.
+GTEST_DECLARE_bool_(catch_exceptions);
+
+// This flag enables using colors in terminal output. Available values are
+// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
+// to let Google Test decide.
+GTEST_DECLARE_string_(color);
+
+// This flag sets up the filter to select by name using a glob pattern
+// the tests to run. If the filter is not given all tests are executed.
+GTEST_DECLARE_string_(filter);
+
+// This flag causes the Google Test to list tests. None of the tests listed
+// are actually run if the flag is provided.
+GTEST_DECLARE_bool_(list_tests);
+
+// This flag controls whether Google Test emits a detailed XML report to a file
+// in addition to its normal textual output.
+GTEST_DECLARE_string_(output);
+
+// This flags control whether Google Test prints the elapsed time for each
+// test.
+GTEST_DECLARE_bool_(print_time);
+
+// This flag specifies the random number seed.
+GTEST_DECLARE_int32_(random_seed);
+
+// This flag sets how many times the tests are repeated. The default value
+// is 1. If the value is -1 the tests are repeating forever.
+GTEST_DECLARE_int32_(repeat);
+
+// This flag controls whether Google Test includes Google Test internal
+// stack frames in failure stack traces.
+GTEST_DECLARE_bool_(show_internal_stack_frames);
+
+// When this flag is specified, tests' order is randomized on every iteration.
+GTEST_DECLARE_bool_(shuffle);
+
+// This flag specifies the maximum number of stack frames to be
+// printed in a failure message.
+GTEST_DECLARE_int32_(stack_trace_depth);
+
+// When this flag is specified, a failed assertion will throw an
+// exception if exceptions are enabled, or exit the program with a
+// non-zero code otherwise.
+GTEST_DECLARE_bool_(throw_on_failure);
+
+// The upper limit for valid stack trace depths.
+const int kMaxStackTraceDepth = 100;
+
+namespace internal {
+
+class AssertHelper;
+class DefaultGlobalTestPartResultReporter;
+class ExecDeathTest;
+class NoExecDeathTest;
+class FinalSuccessChecker;
+class GTestFlagSaver;
+class TestInfoImpl;
+class TestResultAccessor;
+class TestEventListenersAccessor;
+class TestEventRepeater;
+class WindowsDeathTest;
+class UnitTestImpl* GetUnitTestImpl();
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const String& message);
+class PrettyUnitTestResultPrinter;
+class XmlUnitTestResultPrinter;
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared in gtest-internal.h but defined here, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable) {
+ return (Message() << streamable).GetString();
+}
+
+} // namespace internal
+
+// A class for indicating whether an assertion was successful. When
+// the assertion wasn't successful, the AssertionResult object
+// remembers a non-empty message that describes how it failed.
+//
+// To create an instance of this class, use one of the factory functions
+// (AssertionSuccess() and AssertionFailure()).
+//
+// This class is useful for two purposes:
+// 1. Defining predicate functions to be used with Boolean test assertions
+// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts
+// 2. Defining predicate-format functions to be
+// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
+//
+// For example, if you define IsEven predicate:
+//
+// testing::AssertionResult IsEven(int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess();
+// else
+// return testing::AssertionFailure() << n << " is odd";
+// }
+//
+// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5)))
+// will print the message
+//
+// Value of: IsEven(Fib(5))
+// Actual: false (5 is odd)
+// Expected: true
+//
+// instead of a more opaque
+//
+// Value of: IsEven(Fib(5))
+// Actual: false
+// Expected: true
+//
+// in case IsEven is a simple Boolean predicate.
+//
+// If you expect your predicate to be reused and want to support informative
+// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up
+// about half as often as positive ones in our tests), supply messages for
+// both success and failure cases:
+//
+// testing::AssertionResult IsEven(int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess() << n << " is even";
+// else
+// return testing::AssertionFailure() << n << " is odd";
+// }
+//
+// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print
+//
+// Value of: IsEven(Fib(6))
+// Actual: true (8 is even)
+// Expected: false
+//
+// NB: Predicates that support negative Boolean assertions have reduced
+// performance in positive ones so be careful not to use them in tests
+// that have lots (tens of thousands) of positive Boolean assertions.
+//
+// To use this class with EXPECT_PRED_FORMAT assertions such as:
+//
+// // Verifies that Foo() returns an even number.
+// EXPECT_PRED_FORMAT1(IsEven, Foo());
+//
+// you need to define:
+//
+// testing::AssertionResult IsEven(const char* expr, int n) {
+// if ((n % 2) == 0)
+// return testing::AssertionSuccess();
+// else
+// return testing::AssertionFailure()
+// << "Expected: " << expr << " is even\n Actual: it's " << n;
+// }
+//
+// If Foo() returns 5, you will see the following message:
+//
+// Expected: Foo() is even
+// Actual: it's 5
+//
+class GTEST_API_ AssertionResult {
+ public:
+ // Copy constructor.
+ // Used in EXPECT_TRUE/FALSE(assertion_result).
+ AssertionResult(const AssertionResult& other);
+ // Used in the EXPECT_TRUE/FALSE(bool_expression).
+ explicit AssertionResult(bool success) : success_(success) {}
+
+ // Returns true iff the assertion succeeded.
+ operator bool() const { return success_; } // NOLINT
+
+ // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+ AssertionResult operator!() const;
+
+ // Returns the text streamed into this AssertionResult. Test assertions
+ // use it when they fail (i.e., the predicate's outcome doesn't match the
+ // assertion's expectation). When nothing has been streamed into the
+ // object, returns an empty string.
+ const char* message() const {
+ return message_.get() != NULL && message_->c_str() != NULL ?
+ message_->c_str() : "";
+ }
+ // TODO(vladl@google.com): Remove this after making sure no clients use it.
+ // Deprecated; please use message() instead.
+ const char* failure_message() const { return message(); }
+
+ // Streams a custom failure message into this object.
+ template <typename T> AssertionResult& operator<<(const T& value);
+
+ private:
+ // No implementation - we want AssertionResult to be
+ // copy-constructible but not assignable.
+ void operator=(const AssertionResult& other);
+
+ // Stores result of the assertion predicate.
+ bool success_;
+ // Stores the message describing the condition in case the expectation
+ // construct is not satisfied with the predicate's outcome.
+ // Referenced via a pointer to avoid taking too much stack frame space
+ // with test assertions.
+ internal::scoped_ptr<internal::String> message_;
+}; // class AssertionResult
+
+// Streams a custom failure message into this object.
+template <typename T>
+AssertionResult& AssertionResult::operator<<(const T& value) {
+ Message msg;
+ if (message_.get() != NULL)
+ msg << *message_;
+ msg << value;
+ message_.reset(new internal::String(msg.GetString()));
+ return *this;
+}
+
+// Makes a successful assertion result.
+GTEST_API_ AssertionResult AssertionSuccess();
+
+// Makes a failed assertion result.
+GTEST_API_ AssertionResult AssertionFailure();
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << msg.
+GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
+
+// The abstract class that all tests inherit from.
+//
+// In Google Test, a unit test program contains one or many TestCases, and
+// each TestCase contains one or many Tests.
+//
+// When you define a test using the TEST macro, you don't need to
+// explicitly derive from Test - the TEST macro automatically does
+// this for you.
+//
+// The only time you derive from Test is when defining a test fixture
+// to be used a TEST_F. For example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { ... }
+// virtual void TearDown() { ... }
+// ...
+// };
+//
+// TEST_F(FooTest, Bar) { ... }
+// TEST_F(FooTest, Baz) { ... }
+//
+// Test is not copyable.
+class GTEST_API_ Test {
+ public:
+ friend class internal::TestInfoImpl;
+
+ // Defines types for pointers to functions that set up and tear down
+ // a test case.
+ typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
+ typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
+
+ // The d'tor is virtual as we intend to inherit from Test.
+ virtual ~Test();
+
+ // Sets up the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::SetUpTestCase() before running the first
+ // test in test case Foo. Hence a sub-class can define its own
+ // SetUpTestCase() method to shadow the one defined in the super
+ // class.
+ static void SetUpTestCase() {}
+
+ // Tears down the stuff shared by all tests in this test case.
+ //
+ // Google Test will call Foo::TearDownTestCase() after running the last
+ // test in test case Foo. Hence a sub-class can define its own
+ // TearDownTestCase() method to shadow the one defined in the super
+ // class.
+ static void TearDownTestCase() {}
+
+ // Returns true iff the current test has a fatal failure.
+ static bool HasFatalFailure();
+
+ // Returns true iff the current test has a non-fatal failure.
+ static bool HasNonfatalFailure();
+
+ // Returns true iff the current test has a (either fatal or
+ // non-fatal) failure.
+ static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
+
+ // Logs a property for the current test. Only the last value for a given
+ // key is remembered.
+ // These are public static so they can be called from utility functions
+ // that are not members of the test fixture.
+ // The arguments are const char* instead strings, as Google Test is used
+ // on platforms where string doesn't compile.
+ //
+ // Note that a driving consideration for these RecordProperty methods
+ // was to produce xml output suited to the Greenspan charting utility,
+ // which at present will only chart values that fit in a 32-bit int. It
+ // is the user's responsibility to restrict their values to 32-bit ints
+ // if they intend them to be used with Greenspan.
+ static void RecordProperty(const char* key, const char* value);
+ static void RecordProperty(const char* key, int value);
+
+ protected:
+ // Creates a Test object.
+ Test();
+
+ // Sets up the test fixture.
+ virtual void SetUp();
+
+ // Tears down the test fixture.
+ virtual void TearDown();
+
+ private:
+ // Returns true iff the current test has the same fixture class as
+ // the first test in the current test case.
+ static bool HasSameFixtureClass();
+
+ // Runs the test after the test fixture has been set up.
+ //
+ // A sub-class must implement this to define the test logic.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
+ // Instead, use the TEST or TEST_F macro.
+ virtual void TestBody() = 0;
+
+ // Sets up, executes, and tears down the test.
+ void Run();
+
+ // Uses a GTestFlagSaver to save and restore all Google Test flags.
+ const internal::GTestFlagSaver* const gtest_flag_saver_;
+
+ // Often a user mis-spells SetUp() as Setup() and spends a long time
+ // wondering why it is never called by Google Test. The declaration of
+ // the following method is solely for catching such an error at
+ // compile time:
+ //
+ // - The return type is deliberately chosen to be not void, so it
+ // will be a conflict if a user declares void Setup() in his test
+ // fixture.
+ //
+ // - This method is private, so it will be another compiler error
+ // if a user calls it from his test fixture.
+ //
+ // DO NOT OVERRIDE THIS FUNCTION.
+ //
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+
+ // We disallow copying Tests.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
+};
+
+typedef internal::TimeInMillis TimeInMillis;
+
+// A copyable object representing a user specified test property which can be
+// output as a key/value string pair.
+//
+// Don't inherit from TestProperty as its destructor is not virtual.
+class TestProperty {
+ public:
+ // C'tor. TestProperty does NOT have a default constructor.
+ // Always use this constructor (with parameters) to create a
+ // TestProperty object.
+ TestProperty(const char* a_key, const char* a_value) :
+ key_(a_key), value_(a_value) {
+ }
+
+ // Gets the user supplied key.
+ const char* key() const {
+ return key_.c_str();
+ }
+
+ // Gets the user supplied value.
+ const char* value() const {
+ return value_.c_str();
+ }
+
+ // Sets a new value, overriding the one supplied in the constructor.
+ void SetValue(const char* new_value) {
+ value_ = new_value;
+ }
+
+ private:
+ // The key supplied by the user.
+ internal::String key_;
+ // The value supplied by the user.
+ internal::String value_;
+};
+
+// The result of a single Test. This includes a list of
+// TestPartResults, a list of TestProperties, a count of how many
+// death tests there are in the Test, and how much time it took to run
+// the Test.
+//
+// TestResult is not copyable.
+class GTEST_API_ TestResult {
+ public:
+ // Creates an empty TestResult.
+ TestResult();
+
+ // D'tor. Do not inherit from TestResult.
+ ~TestResult();
+
+ // Gets the number of all test parts. This is the sum of the number
+ // of successful test parts and the number of failed test parts.
+ int total_part_count() const;
+
+ // Returns the number of the test properties.
+ int test_property_count() const;
+
+ // Returns true iff the test passed (i.e. no test part failed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test failed.
+ bool Failed() const;
+
+ // Returns true iff the test fatally failed.
+ bool HasFatalFailure() const;
+
+ // Returns true iff the test has a non-fatal failure.
+ bool HasNonfatalFailure() const;
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns the i-th test part result among all the results. i can range
+ // from 0 to test_property_count() - 1. If i is not in that range, aborts
+ // the program.
+ const TestPartResult& GetTestPartResult(int i) const;
+
+ // Returns the i-th test property. i can range from 0 to
+ // test_property_count() - 1. If i is not in that range, aborts the
+ // program.
+ const TestProperty& GetTestProperty(int i) const;
+
+ private:
+ friend class TestInfo;
+ friend class UnitTest;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::ExecDeathTest;
+ friend class internal::TestInfoImpl;
+ friend class internal::TestResultAccessor;
+ friend class internal::UnitTestImpl;
+ friend class internal::WindowsDeathTest;
+
+ // Gets the vector of TestPartResults.
+ const std::vector<TestPartResult>& test_part_results() const {
+ return test_part_results_;
+ }
+
+ // Gets the vector of TestProperties.
+ const std::vector<TestProperty>& test_properties() const {
+ return test_properties_;
+ }
+
+ // Sets the elapsed time.
+ void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
+
+ // Adds a test property to the list. The property is validated and may add
+ // a non-fatal failure if invalid (e.g., if it conflicts with reserved
+ // key names). If a property is already recorded for the same key, the
+ // value will be updated, rather than storing multiple values for the same
+ // key.
+ void RecordProperty(const TestProperty& test_property);
+
+ // Adds a failure if the key is a reserved attribute of Google Test
+ // testcase tags. Returns true if the property is valid.
+ // TODO(russr): Validate attribute names are legal and human readable.
+ static bool ValidateTestProperty(const TestProperty& test_property);
+
+ // Adds a test part result to the list.
+ void AddTestPartResult(const TestPartResult& test_part_result);
+
+ // Returns the death test count.
+ int death_test_count() const { return death_test_count_; }
+
+ // Increments the death test count, returning the new count.
+ int increment_death_test_count() { return ++death_test_count_; }
+
+ // Clears the test part results.
+ void ClearTestPartResults();
+
+ // Clears the object.
+ void Clear();
+
+ // Protects mutable state of the property vector and of owned
+ // properties, whose values may be updated.
+ internal::Mutex test_properites_mutex_;
+
+ // The vector of TestPartResults
+ std::vector<TestPartResult> test_part_results_;
+ // The vector of TestProperties
+ std::vector<TestProperty> test_properties_;
+ // Running count of death tests.
+ int death_test_count_;
+ // The elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestResult.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
+}; // class TestResult
+
+// A TestInfo object stores the following information about a test:
+//
+// Test case name
+// Test name
+// Whether the test should be run
+// A function pointer that creates the test object when invoked
+// Test result
+//
+// The constructor of TestInfo registers itself with the UnitTest
+// singleton such that the RUN_ALL_TESTS() macro knows which tests to
+// run.
+class GTEST_API_ TestInfo {
+ public:
+ // Destructs a TestInfo object. This function is not virtual, so
+ // don't inherit from TestInfo.
+ ~TestInfo();
+
+ // Returns the test case name.
+ const char* test_case_name() const;
+
+ // Returns the test name.
+ const char* name() const;
+
+ // Returns the test case comment.
+ const char* test_case_comment() const;
+
+ // Returns the test comment.
+ const char* comment() const;
+
+ // Returns true if this test should run, that is if the test is not disabled
+ // (or it is disabled but the also_run_disabled_tests flag has been specified)
+ // and its full name matches the user-specified filter.
+ //
+ // Google Test allows the user to filter the tests by their full names.
+ // The full name of a test Bar in test case Foo is defined as
+ // "Foo.Bar". Only the tests that match the filter will run.
+ //
+ // A filter is a colon-separated list of glob (not regex) patterns,
+ // optionally followed by a '-' and a colon-separated list of
+ // negative patterns (tests to exclude). A test is run if it
+ // matches one of the positive patterns and does not match any of
+ // the negative patterns.
+ //
+ // For example, *A*:Foo.* is a filter that matches any string that
+ // contains the character 'A' or starts with "Foo.".
+ bool should_run() const;
+
+ // Returns the result of the test.
+ const TestResult* result() const;
+
+ private:
+#if GTEST_HAS_DEATH_TEST
+ friend class internal::DefaultDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+ friend class Test;
+ friend class TestCase;
+ friend class internal::TestInfoImpl;
+ friend class internal::UnitTestImpl;
+ friend TestInfo* internal::MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ internal::TypeId fixture_class_id,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ internal::TestFactoryBase* factory);
+
+ // Returns true if this test matches the user-specified filter.
+ bool matches_filter() const;
+
+ // Increments the number of death tests encountered in this test so
+ // far.
+ int increment_death_test_count();
+
+ // Accessors for the implementation object.
+ internal::TestInfoImpl* impl() { return impl_; }
+ const internal::TestInfoImpl* impl() const { return impl_; }
+
+ // Constructs a TestInfo object. The newly constructed instance assumes
+ // ownership of the factory object.
+ TestInfo(const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory);
+
+ // An opaque implementation object.
+ internal::TestInfoImpl* impl_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
+};
+
+// A test case, which consists of a vector of TestInfos.
+//
+// TestCase is not copyable.
+class GTEST_API_ TestCase {
+ public:
+ // Creates a TestCase with the given name.
+ //
+ // TestCase does NOT have a default constructor. Always use this
+ // constructor to create a TestCase object.
+ //
+ // Arguments:
+ //
+ // name: name of the test case
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase(const char* name, const char* comment,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Destructor of TestCase.
+ virtual ~TestCase();
+
+ // Gets the name of the TestCase.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the test case comment.
+ const char* comment() const { return comment_.c_str(); }
+
+ // Returns true if any test in this test case should run.
+ bool should_run() const { return should_run_; }
+
+ // Gets the number of successful tests in this test case.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests in this test case.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests in this test case.
+ int disabled_test_count() const;
+
+ // Get the number of tests in this test case that should run.
+ int test_to_run_count() const;
+
+ // Gets the number of all tests in this test case.
+ int total_test_count() const;
+
+ // Returns true iff the test case passed.
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the test case failed.
+ bool Failed() const { return failed_test_count() > 0; }
+
+ // Returns the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns the i-th test among all the tests. i can range from 0 to
+ // total_test_count() - 1. If i is not in that range, returns NULL.
+ const TestInfo* GetTestInfo(int i) const;
+
+ private:
+ friend class Test;
+ friend class internal::UnitTestImpl;
+
+ // Gets the (mutable) vector of TestInfos in this TestCase.
+ std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
+
+ // Gets the (immutable) vector of TestInfos in this TestCase.
+ const std::vector<TestInfo*>& test_info_list() const {
+ return test_info_list_;
+ }
+
+ // Returns the i-th test among all the tests. i can range from 0 to
+ // total_test_count() - 1. If i is not in that range, returns NULL.
+ TestInfo* GetMutableTestInfo(int i);
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Adds a TestInfo to this test case. Will delete the TestInfo upon
+ // destruction of the TestCase object.
+ void AddTestInfo(TestInfo * test_info);
+
+ // Clears the results of all tests in this test case.
+ void ClearResult();
+
+ // Clears the results of all tests in the given test case.
+ static void ClearTestCaseResult(TestCase* test_case) {
+ test_case->ClearResult();
+ }
+
+ // Runs every test in this TestCase.
+ void Run();
+
+ // Returns true iff test passed.
+ static bool TestPassed(const TestInfo * test_info);
+
+ // Returns true iff test failed.
+ static bool TestFailed(const TestInfo * test_info);
+
+ // Returns true iff test is disabled.
+ static bool TestDisabled(const TestInfo * test_info);
+
+ // Returns true if the given test should run.
+ static bool ShouldRunTest(const TestInfo *test_info);
+
+ // Shuffles the tests in this test case.
+ void ShuffleTests(internal::Random* random);
+
+ // Restores the test order to before the first shuffle.
+ void UnshuffleTests();
+
+ // Name of the test case.
+ internal::String name_;
+ // Comment on the test case.
+ internal::String comment_;
+ // The vector of TestInfos in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestInfo*> test_info_list_;
+ // Provides a level of indirection for the test list to allow easy
+ // shuffling and restoring the test order. The i-th element in this
+ // vector is the index of the i-th test in the shuffled test list.
+ std::vector<int> test_indices_;
+ // Pointer to the function that sets up the test case.
+ Test::SetUpTestCaseFunc set_up_tc_;
+ // Pointer to the function that tears down the test case.
+ Test::TearDownTestCaseFunc tear_down_tc_;
+ // True iff any test in this test case should run.
+ bool should_run_;
+ // Elapsed time, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+ // We disallow copying TestCases.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
+};
+
+// An Environment object is capable of setting up and tearing down an
+// environment. The user should subclass this to define his own
+// environment(s).
+//
+// An Environment object does the set-up and tear-down in virtual
+// methods SetUp() and TearDown() instead of the constructor and the
+// destructor, as:
+//
+// 1. You cannot safely throw from a destructor. This is a problem
+// as in some cases Google Test is used where exceptions are enabled, and
+// we may want to implement ASSERT_* using exceptions where they are
+// available.
+// 2. You cannot use ASSERT_* directly in a constructor or
+// destructor.
+class Environment {
+ public:
+ // The d'tor is virtual as we need to subclass Environment.
+ virtual ~Environment() {}
+
+ // Override this to define how to set up the environment.
+ virtual void SetUp() {}
+
+ // Override this to define how to tear down the environment.
+ virtual void TearDown() {}
+ private:
+ // If you see an error about overriding the following function or
+ // about it being private, you have mis-spelled SetUp() as Setup().
+ struct Setup_should_be_spelled_SetUp {};
+ virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
+};
+
+// The interface for tracing execution of tests. The methods are organized in
+// the order the corresponding events are fired.
+class TestEventListener {
+ public:
+ virtual ~TestEventListener() {}
+
+ // Fired before any test activity starts.
+ virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;
+
+ // Fired before each iteration of tests starts. There may be more than
+ // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration
+ // index, starting from 0.
+ virtual void OnTestIterationStart(const UnitTest& unit_test,
+ int iteration) = 0;
+
+ // Fired before environment set-up for each iteration of tests starts.
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;
+
+ // Fired after environment set-up for each iteration of tests ends.
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;
+
+ // Fired before the test case starts.
+ virtual void OnTestCaseStart(const TestCase& test_case) = 0;
+
+ // Fired before the test starts.
+ virtual void OnTestStart(const TestInfo& test_info) = 0;
+
+ // Fired after a failed assertion or a SUCCESS().
+ virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
+
+ // Fired after the test ends.
+ virtual void OnTestEnd(const TestInfo& test_info) = 0;
+
+ // Fired after the test case ends.
+ virtual void OnTestCaseEnd(const TestCase& test_case) = 0;
+
+ // Fired before environment tear-down for each iteration of tests starts.
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;
+
+ // Fired after environment tear-down for each iteration of tests ends.
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;
+
+ // Fired after each iteration of tests finishes.
+ virtual void OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration) = 0;
+
+ // Fired after all test activities have ended.
+ virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
+};
+
+// The convenience class for users who need to override just one or two
+// methods and are not concerned that a possible change to a signature of
+// the methods they override will not be caught during the build. For
+// comments about each method please see the definition of TestEventListener
+// above.
+class EmptyTestEventListener : public TestEventListener {
+ public:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {}
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
+ virtual void OnTestStart(const TestInfo& /*test_info*/) {}
+ virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {}
+ virtual void OnTestEnd(const TestInfo& /*test_info*/) {}
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {}
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+};
+
+// TestEventListeners lets users add listeners to track events in Google Test.
+class GTEST_API_ TestEventListeners {
+ public:
+ TestEventListeners();
+ ~TestEventListeners();
+
+ // Appends an event listener to the end of the list. Google Test assumes
+ // the ownership of the listener (i.e. it will delete the listener when
+ // the test program finishes).
+ void Append(TestEventListener* listener);
+
+ // Removes the given event listener from the list and returns it. It then
+ // becomes the caller's responsibility to delete the listener. Returns
+ // NULL if the listener is not found in the list.
+ TestEventListener* Release(TestEventListener* listener);
+
+ // Returns the standard listener responsible for the default console
+ // output. Can be removed from the listeners list to shut down default
+ // console output. Note that removing this object from the listener list
+ // with Release transfers its ownership to the caller and makes this
+ // function return NULL the next time.
+ TestEventListener* default_result_printer() const {
+ return default_result_printer_;
+ }
+
+ // Returns the standard listener responsible for the default XML output
+ // controlled by the --gtest_output=xml flag. Can be removed from the
+ // listeners list by users who want to shut down the default XML output
+ // controlled by this flag and substitute it with custom one. Note that
+ // removing this object from the listener list with Release transfers its
+ // ownership to the caller and makes this function return NULL the next
+ // time.
+ TestEventListener* default_xml_generator() const {
+ return default_xml_generator_;
+ }
+
+ private:
+ friend class TestCase;
+ friend class internal::DefaultGlobalTestPartResultReporter;
+ friend class internal::NoExecDeathTest;
+ friend class internal::TestEventListenersAccessor;
+ friend class internal::TestInfoImpl;
+ friend class internal::UnitTestImpl;
+
+ // Returns repeater that broadcasts the TestEventListener events to all
+ // subscribers.
+ TestEventListener* repeater();
+
+ // Sets the default_result_printer attribute to the provided listener.
+ // The listener is also added to the listener list and previous
+ // default_result_printer is removed from it and deleted. The listener can
+ // also be NULL in which case it will not be added to the list. Does
+ // nothing if the previous and the current listener objects are the same.
+ void SetDefaultResultPrinter(TestEventListener* listener);
+
+ // Sets the default_xml_generator attribute to the provided listener. The
+ // listener is also added to the listener list and previous
+ // default_xml_generator is removed from it and deleted. The listener can
+ // also be NULL in which case it will not be added to the list. Does
+ // nothing if the previous and the current listener objects are the same.
+ void SetDefaultXmlGenerator(TestEventListener* listener);
+
+ // Controls whether events will be forwarded by the repeater to the
+ // listeners in the list.
+ bool EventForwardingEnabled() const;
+ void SuppressEventForwarding();
+
+ // The actual list of listeners.
+ internal::TestEventRepeater* repeater_;
+ // Listener responsible for the standard result output.
+ TestEventListener* default_result_printer_;
+ // Listener responsible for the creation of the XML output file.
+ TestEventListener* default_xml_generator_;
+
+ // We disallow copying TestEventListeners.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
+};
+
+// A UnitTest consists of a vector of TestCases.
+//
+// This is a singleton class. The only instance of UnitTest is
+// created when UnitTest::GetInstance() is first called. This
+// instance is never deleted.
+//
+// UnitTest is not copyable.
+//
+// This class is thread-safe as long as the methods are called
+// according to their specification.
+class GTEST_API_ UnitTest {
+ public:
+ // Gets the singleton UnitTest object. The first time this method
+ // is called, a UnitTest object is constructed and returned.
+ // Consecutive calls will return the same object.
+ static UnitTest* GetInstance();
+
+ // Runs all tests in this UnitTest object and prints the result.
+ // Returns 0 if successful, or 1 otherwise.
+ //
+ // This method can only be called from the main thread.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ int Run() GTEST_MUST_USE_RESULT_;
+
+ // Returns the working directory when the first TEST() or TEST_F()
+ // was executed. The UnitTest object owns the string.
+ const char* original_working_dir() const;
+
+ // Returns the TestCase object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestCase* current_test_case() const;
+
+ // Returns the TestInfo object for the test that's currently running,
+ // or NULL if no test is running.
+ const TestInfo* current_test_info() const;
+
+ // Returns the random seed used at the start of the current test run.
+ int random_seed() const;
+
+#if GTEST_HAS_PARAM_TEST
+ // Returns the ParameterizedTestCaseRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ //
+ // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+ internal::ParameterizedTestCaseRegistry& parameterized_test_registry();
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Gets the number of successful test cases.
+ int successful_test_case_count() const;
+
+ // Gets the number of failed test cases.
+ int failed_test_case_count() const;
+
+ // Gets the number of all test cases.
+ int total_test_case_count() const;
+
+ // Gets the number of all test cases that contain at least one test
+ // that should run.
+ int test_case_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const;
+
+ // Returns true iff the unit test passed (i.e. all test cases passed).
+ bool Passed() const;
+
+ // Returns true iff the unit test failed (i.e. some test case failed
+ // or something outside of all tests failed).
+ bool Failed() const;
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ const TestCase* GetTestCase(int i) const;
+
+ // Returns the list of event listeners that can be used to track events
+ // inside Google Test.
+ TestEventListeners& listeners();
+
+ private:
+ // Registers and returns a global test environment. When a test
+ // program is run, all global test environments will be set-up in
+ // the order they were registered. After all tests in the program
+ // have finished, all global test environments will be torn-down in
+ // the *reverse* order they were registered.
+ //
+ // The UnitTest object takes ownership of the given environment.
+ //
+ // This method can only be called from the main thread.
+ Environment* AddEnvironment(Environment* env);
+
+ // Adds a TestPartResult to the current TestResult object. All
+ // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
+ // eventually call this to report their results. The user code
+ // should use the assertion macros instead of calling this directly.
+ void AddTestPartResult(TestPartResult::Type result_type,
+ const char* file_name,
+ int line_number,
+ const internal::String& message,
+ const internal::String& os_stack_trace);
+
+ // Adds a TestProperty to the current TestResult object. If the result already
+ // contains a property with the same key, the value will be updated.
+ void RecordPropertyForCurrentTest(const char* key, const char* value);
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ TestCase* GetMutableTestCase(int i);
+
+ // Accessors for the implementation object.
+ internal::UnitTestImpl* impl() { return impl_; }
+ const internal::UnitTestImpl* impl() const { return impl_; }
+
+ // These classes and funcions are friends as they need to access private
+ // members of UnitTest.
+ friend class Test;
+ friend class internal::AssertHelper;
+ friend class internal::ScopedTrace;
+ friend Environment* AddGlobalTestEnvironment(Environment* env);
+ friend internal::UnitTestImpl* internal::GetUnitTestImpl();
+ friend void internal::ReportFailureInUnknownLocation(
+ TestPartResult::Type result_type,
+ const internal::String& message);
+
+ // Creates an empty UnitTest.
+ UnitTest();
+
+ // D'tor
+ virtual ~UnitTest();
+
+ // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+ // Google Test trace stack.
+ void PushGTestTrace(const internal::TraceInfo& trace);
+
+ // Pops a trace from the per-thread Google Test trace stack.
+ void PopGTestTrace();
+
+ // Protects mutable state in *impl_. This is mutable as some const
+ // methods need to lock it too.
+ mutable internal::Mutex mutex_;
+
+ // Opaque implementation object. This field is never changed once
+ // the object is constructed. We don't mark it as const here, as
+ // doing so will cause a warning in the constructor of UnitTest.
+ // Mutable state in *impl_ is protected by mutex_.
+ internal::UnitTestImpl* impl_;
+
+ // We disallow copying UnitTest.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
+};
+
+// A convenient wrapper for adding an environment for the test
+// program.
+//
+// You should call this before RUN_ALL_TESTS() is called, probably in
+// main(). If you use gtest_main, you need to call this before main()
+// starts for it to take effect. For example, you can define a global
+// variable like this:
+//
+// testing::Environment* const foo_env =
+// testing::AddGlobalTestEnvironment(new FooEnvironment);
+//
+// However, we strongly recommend you to write your own main() and
+// call AddGlobalTestEnvironment() there, as relying on initialization
+// of global variables makes the code harder to read and may cause
+// problems when you register multiple environments from different
+// translation units and the environments have dependencies among them
+// (remember that the compiler doesn't guarantee the order in which
+// global variables from different translation units are initialized).
+inline Environment* AddGlobalTestEnvironment(Environment* env) {
+ return UnitTest::GetInstance()->AddEnvironment(env);
+}
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+GTEST_API_ void InitGoogleTest(int* argc, char** argv);
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
+
+namespace internal {
+
+// These overloaded versions handle ::std::string and ::std::wstring.
+GTEST_API_ inline String FormatForFailureMessage(const ::std::string& str) {
+ return (Message() << '"' << str << '"').GetString();
+}
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ inline String FormatForFailureMessage(const ::std::wstring& wstr) {
+ return (Message() << "L\"" << wstr << '"').GetString();
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+// These overloaded versions handle ::string and ::wstring.
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_API_ inline String FormatForFailureMessage(const ::string& str) {
+ return (Message() << '"' << str << '"').GetString();
+}
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_API_ inline String FormatForFailureMessage(const ::wstring& wstr) {
+ return (Message() << "L\"" << wstr << '"').GetString();
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message. The type (but not value)
+// of the other operand may affect the format. This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char*, and print it as a C string when it is compared against an
+// std::string object, for example.
+//
+// The default implementation ignores the type of the other operand.
+// Some specialized versions are used to handle formatting wide or
+// narrow C strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+String FormatForComparisonFailureMessage(const T1& value,
+ const T2& /* other_operand */) {
+ return FormatForFailureMessage(value);
+}
+
+// The helper function for {ASSERT|EXPECT}_EQ.
+template <typename T1, typename T2>
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+#ifdef _MSC_VER
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4389) // Temporarily disables warning on
+ // signed/unsigned mismatch.
+#endif
+
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+#ifdef _MSC_VER
+#pragma warning(pop) // Restores the warning state.
+#endif
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// With this overloaded version, we allow anonymous enums to be used
+// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
+// can be implicitly cast to BiggestInt.
+GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual);
+
+// The helper class for {ASSERT|EXPECT}_EQ. The template argument
+// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
+// is a null pointer literal. The following default implementation is
+// for lhs_is_null_literal being false.
+template <bool lhs_is_null_literal>
+class EqHelper {
+ public:
+ // This templatized version is for the general case.
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // With this overloaded version, we allow anonymous enums to be used
+ // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
+ // enums can be implicitly cast to BiggestInt.
+ //
+ // Even though its body looks the same as the above version, we
+ // cannot merge the two, as it will make anonymous enums unhappy.
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+};
+
+// This specialization is used when the first argument to ASSERT_EQ()
+// is a null pointer literal.
+template <>
+class EqHelper<true> {
+ public:
+ // We define two overloaded versions of Compare(). The first
+ // version will be picked when the second argument to ASSERT_EQ() is
+ // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
+ // EXPECT_EQ(false, a_bool).
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& expected,
+ const T2& actual) {
+ return CmpHelperEQ(expected_expression, actual_expression, expected,
+ actual);
+ }
+
+ // This version will be picked when the second argument to
+ // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer).
+ template <typename T1, typename T2>
+ static AssertionResult Compare(const char* expected_expression,
+ const char* actual_expression,
+ const T1& /* expected */,
+ T2* actual) {
+ // We already know that 'expected' is a null pointer.
+ return CmpHelperEQ(expected_expression, actual_expression,
+ static_cast<T2*>(NULL), actual);
+ }
+};
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste
+// of similar code.
+//
+// For each templatized helper function, we also define an overloaded
+// version for BiggestInt in order to reduce code bloat and allow
+// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
+// with gcc 4.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+template <typename T1, typename T2>\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ const T1& val1, const T2& val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ Message msg;\
+ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ return AssertionFailure(msg);\
+ }\
+}\
+GTEST_API_ AssertionResult CmpHelper##op_name(\
+ const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2)
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// Implements the helper function for {ASSERT|EXPECT}_NE
+GTEST_IMPL_CMP_HELPER_(NE, !=);
+// Implements the helper function for {ASSERT|EXPECT}_LE
+GTEST_IMPL_CMP_HELPER_(LE, <=);
+// Implements the helper function for {ASSERT|EXPECT}_LT
+GTEST_IMPL_CMP_HELPER_(LT, < );
+// Implements the helper function for {ASSERT|EXPECT}_GE
+GTEST_IMPL_CMP_HELPER_(GE, >=);
+// Implements the helper function for {ASSERT|EXPECT}_GT
+GTEST_IMPL_CMP_HELPER_(GT, > );
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual);
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2);
+
+
+// Helper function for *_STREQ on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual);
+
+// Helper function for *_STRNE on wide strings.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2);
+
+} // namespace internal
+
+// IsSubstring() and IsNotSubstring() are intended to be used as the
+// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
+// themselves. They check whether needle is a substring of haystack
+// (NULL is considered a substring of itself only), and return an
+// appropriate error message when they fail.
+//
+// The {needle,haystack}_expr arguments are the stringified
+// expressions that generated the two real arguments.
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack);
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack);
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_API_ AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+GTEST_API_ AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack);
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+// Helper template function for comparing floating-points.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename RawType>
+AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
+ const char* actual_expression,
+ RawType expected,
+ RawType actual) {
+ const FloatingPoint<RawType> lhs(expected), rhs(actual);
+
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ StrStream expected_ss;
+ expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << expected;
+
+ StrStream actual_ss;
+ actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << actual;
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ StrStreamToString(&expected_ss),
+ StrStreamToString(&actual_ss),
+ false);
+}
+
+// Helper function for implementing ASSERT_NEAR.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error);
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+// A class that enables one to stream messages to assertion macros
+class GTEST_API_ AssertHelper {
+ public:
+ // Constructor.
+ AssertHelper(TestPartResult::Type type,
+ const char* file,
+ int line,
+ const char* message);
+ ~AssertHelper();
+
+ // Message assignment is a semantic trick to enable assertion
+ // streaming; see the GTEST_MESSAGE_ macro below.
+ void operator=(const Message& message) const;
+
+ private:
+ // We put our data in a struct so that the size of the AssertHelper class can
+ // be as small as possible. This is important because gcc is incapable of
+ // re-using stack space even for temporary variables, so every EXPECT_EQ
+ // reserves stack space for another AssertHelper.
+ struct AssertHelperData {
+ AssertHelperData(TestPartResult::Type t,
+ const char* srcfile,
+ int line_num,
+ const char* msg)
+ : type(t), file(srcfile), line(line_num), message(msg) { }
+
+ TestPartResult::Type const type;
+ const char* const file;
+ int const line;
+ String const message;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
+ };
+
+ AssertHelperData* const data_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
+};
+
+} // namespace internal
+
+#if GTEST_HAS_PARAM_TEST
+// The abstract base class that all value-parameterized tests inherit from.
+//
+// This class adds support for accessing the test parameter value via
+// the GetParam() method.
+//
+// Use it with one of the parameter generator defining functions, like Range(),
+// Values(), ValuesIn(), Bool(), and Combine().
+//
+// class FooTest : public ::testing::TestWithParam<int> {
+// protected:
+// FooTest() {
+// // Can use GetParam() here.
+// }
+// virtual ~FooTest() {
+// // Can use GetParam() here.
+// }
+// virtual void SetUp() {
+// // Can use GetParam() here.
+// }
+// virtual void TearDown {
+// // Can use GetParam() here.
+// }
+// };
+// TEST_P(FooTest, DoesBar) {
+// // Can use GetParam() method here.
+// Foo foo;
+// ASSERT_TRUE(foo.DoesBar(GetParam()));
+// }
+// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
+
+template <typename T>
+class TestWithParam : public Test {
+ public:
+ typedef T ParamType;
+
+ // The current parameter value. Is also available in the test fixture's
+ // constructor.
+ const ParamType& GetParam() const { return *parameter_; }
+
+ private:
+ // Sets parameter value. The caller is responsible for making sure the value
+ // remains alive and unchanged throughout the current test.
+ static void SetParam(const ParamType* parameter) {
+ parameter_ = parameter;
+ }
+
+ // Static value used for accessing parameter during a test lifetime.
+ static const ParamType* parameter_;
+
+ // TestClass must be a subclass of TestWithParam<T>.
+ template <class TestClass> friend class internal::ParameterizedTestFactory;
+};
+
+template <typename T>
+const T* TestWithParam<T>::parameter_ = NULL;
+
+#endif // GTEST_HAS_PARAM_TEST
+
+// Macros for indicating success/failure in test code.
+
+// ADD_FAILURE unconditionally adds a failure to the current test.
+// SUCCEED generates a success - it doesn't automatically make the
+// current test successful, as a test is only successful when it has
+// no failure.
+//
+// EXPECT_* verifies that a certain condition is satisfied. If not,
+// it behaves like ADD_FAILURE. In particular:
+//
+// EXPECT_TRUE verifies that a Boolean condition is true.
+// EXPECT_FALSE verifies that a Boolean condition is false.
+//
+// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
+// that they will also abort the current function on failure. People
+// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
+// writing data-driven tests often find themselves using ADD_FAILURE
+// and EXPECT_* more.
+//
+// Examples:
+//
+// EXPECT_TRUE(server.StatusIsOK());
+// ASSERT_FALSE(server.HasPendingRequest(port))
+// << "There are still pending requests " << "on port " << port;
+
+// Generates a nonfatal failure with a generic message.
+#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
+
+// Generates a fatal failure with a generic message.
+#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
+
+// Define this macro to 1 to omit the definition of FAIL(), which is a
+// generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_FAIL
+#define FAIL() GTEST_FAIL()
+#endif
+
+// Generates a success with a generic message.
+#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")
+
+// Define this macro to 1 to omit the definition of SUCCEED(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_SUCCEED
+#define SUCCEED() GTEST_SUCCEED()
+#endif
+
+// Macros for testing exceptions.
+//
+// * {ASSERT|EXPECT}_THROW(statement, expected_exception):
+// Tests that the statement throws the expected exception.
+// * {ASSERT|EXPECT}_NO_THROW(statement):
+// Tests that the statement doesn't throw any exception.
+// * {ASSERT|EXPECT}_ANY_THROW(statement):
+// Tests that the statement throws an exception.
+
+#define EXPECT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_THROW(statement, expected_exception) \
+ GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
+#define ASSERT_NO_THROW(statement) \
+ GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
+#define ASSERT_ANY_THROW(statement) \
+ GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
+
+// Boolean assertions. Condition can be either a Boolean expression or an
+// AssertionResult. For more information on how to use AssertionResult with
+// these macros see comments on that class.
+#define EXPECT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_NONFATAL_FAILURE_)
+#define EXPECT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_NONFATAL_FAILURE_)
+#define ASSERT_TRUE(condition) \
+ GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+ GTEST_FATAL_FAILURE_)
+#define ASSERT_FALSE(condition) \
+ GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
+ GTEST_FATAL_FAILURE_)
+
+// Includes the auto-generated header that implements a family of
+// generic predicate assertion macros.
+#include <gtest/gtest_pred_impl.h>
+
+// Macros for testing equalities and inequalities.
+//
+// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
+// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
+// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
+// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
+// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
+// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
+//
+// When they are not, Google Test prints both the tested expressions and
+// their actual values. The values must be compatible built-in types,
+// or you will get a compiler error. By "compatible" we mean that the
+// values can be compared by the respective operator.
+//
+// Note:
+//
+// 1. It is possible to make a user-defined type work with
+// {ASSERT|EXPECT}_??(), but that requires overloading the
+// comparison operators and is thus discouraged by the Google C++
+// Usage Guide. Therefore, you are advised to use the
+// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
+// equal.
+//
+// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
+// pointers (in particular, C strings). Therefore, if you use it
+// with two C strings, you are testing how their locations in memory
+// are related, not how their content is related. To compare two C
+// strings by content, use {ASSERT|EXPECT}_STR*().
+//
+// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
+// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+// what the actual value is when it fails, and similarly for the
+// other comparisons.
+//
+// 4. Do not depend on the order in which {ASSERT|EXPECT}_??()
+// evaluate their arguments, which is undefined.
+//
+// 5. These macros evaluate their arguments exactly once.
+//
+// Examples:
+//
+// EXPECT_NE(5, Foo());
+// EXPECT_EQ(NULL, a_pointer);
+// ASSERT_LT(i, array_size);
+// ASSERT_GT(records.size(), 0) << "There is no record left.";
+
+#define EXPECT_EQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+ expected, actual)
+#define EXPECT_NE(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+#define EXPECT_LE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define EXPECT_LT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define EXPECT_GE(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define EXPECT_GT(val1, val2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+#define ASSERT_EQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal:: \
+ EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
+ expected, actual)
+#define ASSERT_NE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
+#define ASSERT_LE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
+#define ASSERT_LT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
+#define ASSERT_GE(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
+#define ASSERT_GT(val1, val2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
+
+// C String Comparisons. All tests treat NULL and any non-NULL string
+// as different. Two NULLs are equal.
+//
+// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
+// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2
+// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
+// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
+//
+// For wide or narrow string objects, you can use the
+// {ASSERT|EXPECT}_??() macros.
+//
+// Don't depend on the order in which the arguments are evaluated,
+// which is undefined.
+//
+// These macros evaluate their arguments exactly once.
+
+#define EXPECT_STREQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STRNE(s1, s2) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define EXPECT_STRCASEEQ(expected, actual) \
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASENE(s1, s2)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+#define ASSERT_STREQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STRNE(s1, s2) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
+#define ASSERT_STRCASEEQ(expected, actual) \
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASENE(s1, s2)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
+
+// Macros for comparing floating-point numbers.
+//
+// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+// Tests that two float values are almost equal.
+// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+// Tests that two double values are almost equal.
+// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
+// Tests that v1 and v2 are within the given distance to each other.
+//
+// Google Test uses ULP-based comparison to automatically pick a default
+// error bound that is appropriate for the operands. See the
+// FloatingPoint template class in gtest-internal.h if you are
+// interested in the implementation details.
+
+#define EXPECT_FLOAT_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define EXPECT_DOUBLE_EQ(expected, actual)\
+ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define ASSERT_FLOAT_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
+ expected, actual)
+
+#define ASSERT_DOUBLE_EQ(expected, actual)\
+ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
+ expected, actual)
+
+#define EXPECT_NEAR(val1, val2, abs_error)\
+ EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+#define ASSERT_NEAR(val1, val2, abs_error)\
+ ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
+ val1, val2, abs_error)
+
+// These predicate format functions work on floating-point values, and
+// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
+//
+// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2);
+GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2);
+
+
+#if GTEST_OS_WINDOWS
+
+// Macros that test for HRESULT failure and success, these are only useful
+// on Windows, and rely on Windows SDK macros and APIs to compile.
+//
+// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
+//
+// When expr unexpectedly fails or succeeds, Google Test prints the
+// expected result and the actual result with both a human-readable
+// string representation of the error, if available, as well as the
+// hex result code.
+#define EXPECT_HRESULT_SUCCEEDED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+#define ASSERT_HRESULT_SUCCEEDED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
+
+#define EXPECT_HRESULT_FAILED(expr) \
+ EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#define ASSERT_HRESULT_FAILED(expr) \
+ ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
+
+#endif // GTEST_OS_WINDOWS
+
+// Macros that execute statement and check that it doesn't generate new fatal
+// failures in the current thread.
+//
+// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
+//
+// Examples:
+//
+// EXPECT_NO_FATAL_FAILURE(Process());
+// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
+//
+#define ASSERT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
+#define EXPECT_NO_FATAL_FAILURE(statement) \
+ GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
+
+// Causes a trace (including the source file path, the current line
+// number, and the given message) to be included in every test failure
+// message generated by code in the current scope. The effect is
+// undone when the control leaves the current scope.
+//
+// The message argument can be anything streamable to std::ostream.
+//
+// In the implementation, we include the current line number as part
+// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
+// to appear in the same block - as long as they are on different
+// lines.
+#define SCOPED_TRACE(message) \
+ ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
+ __FILE__, __LINE__, ::testing::Message() << (message))
+
+namespace internal {
+
+// This template is declared, but intentionally undefined.
+template <typename T1, typename T2>
+struct StaticAssertTypeEqHelper;
+
+template <typename T>
+struct StaticAssertTypeEqHelper<T, T> {};
+
+} // namespace internal
+
+// Compile-time assertion for type equality.
+// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
+// the same type. The value it returns is not interesting.
+//
+// Instead of making StaticAssertTypeEq a class template, we make it a
+// function template that invokes a helper class template. This
+// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
+// defining objects of that type.
+//
+// CAVEAT:
+//
+// When used inside a method of a class template,
+// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
+// instantiated. For example, given:
+//
+// template <typename T> class Foo {
+// public:
+// void Bar() { testing::StaticAssertTypeEq<int, T>(); }
+// };
+//
+// the code:
+//
+// void Test1() { Foo<bool> foo; }
+//
+// will NOT generate a compiler error, as Foo<bool>::Bar() is never
+// actually instantiated. Instead, you need:
+//
+// void Test2() { Foo<bool> foo; foo.Bar(); }
+//
+// to cause a compiler error.
+template <typename T1, typename T2>
+bool StaticAssertTypeEq() {
+ internal::StaticAssertTypeEqHelper<T1, T2>();
+ return true;
+}
+
+// Defines a test.
+//
+// The first parameter is the name of the test case, and the second
+// parameter is the name of the test within the test case.
+//
+// The convention is to end the test case name with "Test". For
+// example, a test case for the Foo class can be named FooTest.
+//
+// The user should put his test code between braces after using this
+// macro. Example:
+//
+// TEST(FooTest, InitializesCorrectly) {
+// Foo foo;
+// EXPECT_TRUE(foo.StatusIsOK());
+// }
+
+// Note that we call GetTestTypeId() instead of GetTypeId<
+// ::testing::Test>() here to get the type ID of testing::Test. This
+// is to work around a suspected linker bug when using Google Test as
+// a framework on Mac OS X. The bug causes GetTypeId<
+// ::testing::Test>() to return different values depending on whether
+// the call is from the Google Test framework itself or from user test
+// code. GetTestTypeId() is guaranteed to always return the same
+// value, as it always calls GetTypeId<>() from the Google Test
+// framework.
+#define GTEST_TEST(test_case_name, test_name)\
+ GTEST_TEST_(test_case_name, test_name, \
+ ::testing::Test, ::testing::internal::GetTestTypeId())
+
+// Define this macro to 1 to omit the definition of TEST(), which
+// is a generic name and clashes with some other libraries.
+#if !GTEST_DONT_DEFINE_TEST
+#define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
+#endif
+
+// Defines a test that uses a test fixture.
+//
+// The first parameter is the name of the test fixture class, which
+// also doubles as the test case name. The second parameter is the
+// name of the test within the test case.
+//
+// A test fixture class must be declared earlier. The user should put
+// his test code between braces after using this macro. Example:
+//
+// class FooTest : public testing::Test {
+// protected:
+// virtual void SetUp() { b_.AddElement(3); }
+//
+// Foo a_;
+// Foo b_;
+// };
+//
+// TEST_F(FooTest, InitializesCorrectly) {
+// EXPECT_TRUE(a_.StatusIsOK());
+// }
+//
+// TEST_F(FooTest, ReturnsElementCountCorrectly) {
+// EXPECT_EQ(0, a_.size());
+// EXPECT_EQ(1, b_.size());
+// }
+
+#define TEST_F(test_fixture, test_name)\
+ GTEST_TEST_(test_fixture, test_name, test_fixture, \
+ ::testing::internal::GetTypeId<test_fixture>())
+
+// Use this macro in main() to run all tests. It returns 0 if all
+// tests are successful, or 1 otherwise.
+//
+// RUN_ALL_TESTS() should be invoked after the command line has been
+// parsed by InitGoogleTest().
+
+#define RUN_ALL_TESTS()\
+ (::testing::UnitTest::GetInstance()->Run())
+
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest_pred_impl.h b/Source/ThirdParty/gtest/include/gtest/gtest_pred_impl.h
new file mode 100644
index 000000000..e1e2f8c4c
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest_pred_impl.h
@@ -0,0 +1,368 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command
+// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most 5.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \
+ ; \
+ else \
+ on_failure(gtest_ar.failure_message())
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1>
+AssertionResult AssertPred1Helper(const char* pred_text,
+ const char* e1,
+ Pred pred,
+ const T1& v1) {
+ if (pred(v1)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, v1),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
+// this in your code.
+#define GTEST_PRED1_(pred, v1, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
+ #v1, \
+ pred, \
+ v1), on_failure)
+
+// Unary predicate assertion macros.
+#define EXPECT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT1(pred_format, v1) \
+ GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED1(pred, v1) \
+ GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2>
+AssertionResult AssertPred2Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ Pred pred,
+ const T1& v1,
+ const T2& v2) {
+ if (pred(v1, v2)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
+// this in your code.
+#define GTEST_PRED2_(pred, v1, v2, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
+ #v1, \
+ #v2, \
+ pred, \
+ v1, \
+ v2), on_failure)
+
+// Binary predicate assertion macros.
+#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
+ GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED2(pred, v1, v2) \
+ GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3>
+AssertionResult AssertPred3Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3) {
+ if (pred(v1, v2, v3)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
+// this in your code.
+#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ pred, \
+ v1, \
+ v2, \
+ v3), on_failure)
+
+// Ternary predicate assertion macros.
+#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
+ GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED3(pred, v1, v2, v3) \
+ GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4>
+AssertionResult AssertPred4Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) {
+ if (pred(v1, v2, v3, v4)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
+// this in your code.
+#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4), on_failure)
+
+// 4-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
+ GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
+ GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
+
+
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+template <typename Pred,
+ typename T1,
+ typename T2,
+ typename T3,
+ typename T4,
+ typename T5>
+AssertionResult AssertPred5Helper(const char* pred_text,
+ const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ Pred pred,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) {
+ if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
+
+ Message msg;
+ msg << pred_text << "("
+ << e1 << ", "
+ << e2 << ", "
+ << e3 << ", "
+ << e4 << ", "
+ << e5 << ") evaluates to false, where"
+ << "\n" << e1 << " evaluates to " << v1
+ << "\n" << e2 << " evaluates to " << v2
+ << "\n" << e3 << " evaluates to " << v3
+ << "\n" << e4 << " evaluates to " << v4
+ << "\n" << e5 << " evaluates to " << v5;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
+// this in your code.
+#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
+ GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
+ #v1, \
+ #v2, \
+ #v3, \
+ #v4, \
+ #v5, \
+ pred, \
+ v1, \
+ v2, \
+ v3, \
+ v4, \
+ v5), on_failure)
+
+// 5-ary predicate assertion macros.
+#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
+ GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
+ GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
+
+
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/gtest_prod.h b/Source/ThirdParty/gtest/include/gtest/gtest_prod.h
new file mode 100644
index 000000000..da80ddc6c
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/gtest_prod.h
@@ -0,0 +1,58 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Google C++ Testing Framework definitions useful in production code.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
+
+// When you need to test the private or protected members of a class,
+// use the FRIEND_TEST macro to declare your tests as friends of the
+// class. For example:
+//
+// class MyClass {
+// private:
+// void MyMethod();
+// FRIEND_TEST(MyClassTest, MyMethod);
+// };
+//
+// class MyClassTest : public testing::Test {
+// // ...
+// };
+//
+// TEST_F(MyClassTest, MyMethod) {
+// // Can call MyClass::MyMethod() here.
+// }
+
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-death-test-internal.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-death-test-internal.h
new file mode 100644
index 000000000..e4330848d
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-death-test-internal.h
@@ -0,0 +1,275 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines internal utilities needed for implementing
+// death tests. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
+
+#include <gtest/internal/gtest-internal.h>
+
+namespace testing {
+namespace internal {
+
+GTEST_DECLARE_string_(internal_run_death_test);
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kDeathTestStyleFlag[] = "death_test_style";
+const char kDeathTestUseFork[] = "death_test_use_fork";
+const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
+
+#if GTEST_HAS_DEATH_TEST
+
+// DeathTest is a class that hides much of the complexity of the
+// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
+// returns a concrete class that depends on the prevailing death test
+// style, as defined by the --gtest_death_test_style and/or
+// --gtest_internal_run_death_test flags.
+
+// In describing the results of death tests, these terms are used with
+// the corresponding definitions:
+//
+// exit status: The integer exit information in the format specified
+// by wait(2)
+// exit code: The integer code passed to exit(3), _exit(2), or
+// returned from main()
+class GTEST_API_ DeathTest {
+ public:
+ // Create returns false if there was an error determining the
+ // appropriate action to take for the current death test; for example,
+ // if the gtest_death_test_style flag is set to an invalid value.
+ // The LastMessage method will return a more detailed message in that
+ // case. Otherwise, the DeathTest pointer pointed to by the "test"
+ // argument is set. If the death test should be skipped, the pointer
+ // is set to NULL; otherwise, it is set to the address of a new concrete
+ // DeathTest object that controls the execution of the current test.
+ static bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+ DeathTest();
+ virtual ~DeathTest() { }
+
+ // A helper class that aborts a death test when it's deleted.
+ class ReturnSentinel {
+ public:
+ explicit ReturnSentinel(DeathTest* test) : test_(test) { }
+ ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
+ private:
+ DeathTest* const test_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
+ } GTEST_ATTRIBUTE_UNUSED_;
+
+ // An enumeration of possible roles that may be taken when a death
+ // test is encountered. EXECUTE means that the death test logic should
+ // be executed immediately. OVERSEE means that the program should prepare
+ // the appropriate environment for a child process to execute the death
+ // test, then wait for it to complete.
+ enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
+
+ // An enumeration of the two reasons that a test might be aborted.
+ enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE };
+
+ // Assumes one of the above roles.
+ virtual TestRole AssumeRole() = 0;
+
+ // Waits for the death test to finish and returns its status.
+ virtual int Wait() = 0;
+
+ // Returns true if the death test passed; that is, the test process
+ // exited during the test, its exit status matches a user-supplied
+ // predicate, and its stderr output matches a user-supplied regular
+ // expression.
+ // The user-supplied predicate may be a macro expression rather
+ // than a function pointer or functor, or else Wait and Passed could
+ // be combined.
+ virtual bool Passed(bool exit_status_ok) = 0;
+
+ // Signals that the death test did not die as expected.
+ virtual void Abort(AbortReason reason) = 0;
+
+ // Returns a human-readable outcome message regarding the outcome of
+ // the last death test.
+ static const char* LastMessage();
+
+ static void set_last_death_test_message(const String& message);
+
+ private:
+ // A string containing a description of the outcome of the last death test.
+ static String last_death_test_message_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
+};
+
+// Factory interface for death tests. May be mocked out for testing.
+class DeathTestFactory {
+ public:
+ virtual ~DeathTestFactory() { }
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) = 0;
+};
+
+// A concrete DeathTestFactory implementation for normal use.
+class DefaultDeathTestFactory : public DeathTestFactory {
+ public:
+ virtual bool Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test);
+};
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
+
+// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
+// ASSERT_EXIT*, and EXPECT_EXIT*.
+#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ const ::testing::internal::RE& gtest_regex = (regex); \
+ ::testing::internal::DeathTest* gtest_dt; \
+ if (!::testing::internal::DeathTest::Create(#statement, &gtest_regex, \
+ __FILE__, __LINE__, &gtest_dt)) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ if (gtest_dt != NULL) { \
+ ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
+ gtest_dt_ptr(gtest_dt); \
+ switch (gtest_dt->AssumeRole()) { \
+ case ::testing::internal::DeathTest::OVERSEE_TEST: \
+ if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
+ } \
+ break; \
+ case ::testing::internal::DeathTest::EXECUTE_TEST: { \
+ ::testing::internal::DeathTest::ReturnSentinel \
+ gtest_sentinel(gtest_dt); \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
+ break; \
+ } \
+ } \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
+ fail(::testing::internal::DeathTest::LastMessage())
+// The symbol "fail" here expands to something into which a message
+// can be streamed.
+
+// A class representing the parsed contents of the
+// --gtest_internal_run_death_test flag, as it existed when
+// RUN_ALL_TESTS was called.
+class InternalRunDeathTestFlag {
+ public:
+ InternalRunDeathTestFlag(const String& a_file,
+ int a_line,
+ int an_index,
+ int a_write_fd)
+ : file_(a_file), line_(a_line), index_(an_index),
+ write_fd_(a_write_fd) {}
+
+ ~InternalRunDeathTestFlag() {
+ if (write_fd_ >= 0)
+ posix::Close(write_fd_);
+ }
+
+ String file() const { return file_; }
+ int line() const { return line_; }
+ int index() const { return index_; }
+ int write_fd() const { return write_fd_; }
+
+ private:
+ String file_;
+ int line_;
+ int index_;
+ int write_fd_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
+};
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
+
+#else // GTEST_HAS_DEATH_TEST
+
+// This macro is used for implementing macros such as
+// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
+// death tests are not supported. Those macros must compile on such systems
+// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
+// systems that support death tests. This allows one to write such a macro
+// on a system that does not support death tests and be sure that it will
+// compile on a death-test supporting system.
+//
+// Parameters:
+// statement - A statement that a macro such as EXPECT_DEATH would test
+// for program termination. This macro has to make sure this
+// statement is compiled but not executed, to ensure that
+// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
+// parameter iff EXPECT_DEATH compiles with it.
+// regex - A regex that a macro such as EXPECT_DEATH would use to test
+// the output of statement. This parameter has to be
+// compiled but not evaluated by this macro, to ensure that
+// this macro only accepts expressions that a macro such as
+// EXPECT_DEATH would accept.
+// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
+// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
+// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
+// compile inside functions where ASSERT_DEATH doesn't
+// compile.
+//
+// The branch that has an always false condition is used to ensure that
+// statement and regex are compiled (and thus syntactically correct) but
+// never executed. The unreachable code macro protects the terminator
+// statement from generating an 'unreachable code' warning in case
+// statement unconditionally returns or throws. The Message constructor at
+// the end allows the syntax of streaming additional messages into the
+// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
+#define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::AlwaysTrue()) { \
+ GTEST_LOG_(WARNING) \
+ << "Death tests are not supported on this platform.\n" \
+ << "Statement '" #statement "' cannot be verified."; \
+ } else if (::testing::internal::AlwaysFalse()) { \
+ ::testing::internal::RE::PartialMatch(".*", (regex)); \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ terminator; \
+ } else \
+ ::testing::Message()
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-filepath.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-filepath.h
new file mode 100644
index 000000000..4b76d7950
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-filepath.h
@@ -0,0 +1,210 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray@gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This header file declares classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included in <gtest/internal/gtest-internal.h>.
+// Do not include this header file separately!
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
+
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+namespace internal {
+
+// FilePath - a class for file and directory pathname manipulation which
+// handles platform-specific conventions (like the pathname separator).
+// Used for helper functions for naming files in a directory for xml output.
+// Except for Set methods, all methods are const or static, which provides an
+// "immutable value object" -- useful for peace of mind.
+// A FilePath with a value ending in a path separator ("like/this/") represents
+// a directory, otherwise it is assumed to represent a file. In either case,
+// it may or may not represent an actual file or directory in the file system.
+// Names are NOT checked for syntax correctness -- no checking for illegal
+// characters, malformed paths, etc.
+
+class GTEST_API_ FilePath {
+ public:
+ FilePath() : pathname_("") { }
+ FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
+
+ explicit FilePath(const char* pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ explicit FilePath(const String& pathname) : pathname_(pathname) {
+ Normalize();
+ }
+
+ FilePath& operator=(const FilePath& rhs) {
+ Set(rhs);
+ return *this;
+ }
+
+ void Set(const FilePath& rhs) {
+ pathname_ = rhs.pathname_;
+ }
+
+ String ToString() const { return pathname_; }
+ const char* c_str() const { return pathname_.c_str(); }
+
+ // Returns the current working directory, or "" if unsuccessful.
+ static FilePath GetCurrentDir();
+
+ // Given directory = "dir", base_name = "test", number = 0,
+ // extension = "xml", returns "dir/test.xml". If number is greater
+ // than zero (e.g., 12), returns "dir/test_12.xml".
+ // On Windows platform, uses \ as the separator rather than /.
+ static FilePath MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension);
+
+ // Given directory = "dir", relative_path = "test.xml",
+ // returns "dir/test.xml".
+ // On Windows, uses \ as the separator rather than /.
+ static FilePath ConcatPaths(const FilePath& directory,
+ const FilePath& relative_path);
+
+ // Returns a pathname for a file that does not currently exist. The pathname
+ // will be directory/base_name.extension or
+ // directory/base_name_<number>.extension if directory/base_name.extension
+ // already exists. The number will be incremented until a pathname is found
+ // that does not already exist.
+ // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+ // There could be a race condition if two or more processes are calling this
+ // function at the same time -- they could both pick the same filename.
+ static FilePath GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension);
+
+ // Returns true iff the path is NULL or "".
+ bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }
+
+ // If input name has a trailing separator character, removes it and returns
+ // the name, otherwise return the name string unmodified.
+ // On Windows platform, uses \ as the separator, other platforms use /.
+ FilePath RemoveTrailingPathSeparator() const;
+
+ // Returns a copy of the FilePath with the directory part removed.
+ // Example: FilePath("path/to/file").RemoveDirectoryName() returns
+ // FilePath("file"). If there is no directory part ("just_a_file"), it returns
+ // the FilePath unmodified. If there is no file part ("just_a_dir/") it
+ // returns an empty FilePath ("").
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveDirectoryName() const;
+
+ // RemoveFileName returns the directory path with the filename removed.
+ // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+ // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+ // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+ // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
+ FilePath RemoveFileName() const;
+
+ // Returns a copy of the FilePath with the case-insensitive extension removed.
+ // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+ // FilePath("dir/file"). If a case-insensitive extension is not
+ // found, returns a copy of the original FilePath.
+ FilePath RemoveExtension(const char* extension) const;
+
+ // Creates directories so that path exists. Returns true if successful or if
+ // the directories already exist; returns false if unable to create
+ // directories for any reason. Will also return false if the FilePath does
+ // not represent a directory (that is, it doesn't end with a path separator).
+ bool CreateDirectoriesRecursively() const;
+
+ // Create the directory so that path exists. Returns true if successful or
+ // if the directory already exists; returns false if unable to create the
+ // directory for any reason, including if the parent directory does not
+ // exist. Not named "CreateDirectory" because that's a macro on Windows.
+ bool CreateFolder() const;
+
+ // Returns true if FilePath describes something in the file-system,
+ // either a file, directory, or whatever, and that something exists.
+ bool FileOrDirectoryExists() const;
+
+ // Returns true if pathname describes a directory in the file-system
+ // that exists.
+ bool DirectoryExists() const;
+
+ // Returns true if FilePath ends with a path separator, which indicates that
+ // it is intended to represent a directory. Returns false otherwise.
+ // This does NOT check that a directory (or file) actually exists.
+ bool IsDirectory() const;
+
+ // Returns true if pathname describes a root directory. (Windows has one
+ // root directory per disk drive.)
+ bool IsRootDirectory() const;
+
+ // Returns true if pathname describes an absolute path.
+ bool IsAbsolutePath() const;
+
+ private:
+ // Replaces multiple consecutive separators with a single separator.
+ // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+ // redundancies that might be in a pathname involving "." or "..".
+ //
+ // A pathname with multiple consecutive separators may occur either through
+ // user error or as a result of some scripts or APIs that generate a pathname
+ // with a trailing separator. On other platforms the same API or script
+ // may NOT generate a pathname with a trailing "/". Then elsewhere that
+ // pathname may have another "/" and pathname components added to it,
+ // without checking for the separator already being there.
+ // The script language and operating system may allow paths like "foo//bar"
+ // but some of the functions in FilePath will not handle that correctly. In
+ // particular, RemoveTrailingPathSeparator() only removes one separator, and
+ // it is called in CreateDirectoriesRecursively() assuming that it will change
+ // a pathname from directory syntax (trailing separator) to filename syntax.
+ //
+ // On Windows this method also replaces the alternate path separator '/' with
+ // the primary path separator '\\', so that for example "bar\\/\\foo" becomes
+ // "bar\\foo".
+
+ void Normalize();
+
+ // Returns a pointer to the last occurence of a valid path separator in
+ // the FilePath. On Windows, for example, both '/' and '\' are valid path
+ // separators. Returns NULL if no path separator was found.
+ const char* FindLastPathSeparator() const;
+
+ String pathname_;
+}; // class FilePath
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-internal.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-internal.h
new file mode 100644
index 000000000..31a66e99d
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-internal.h
@@ -0,0 +1,923 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares functions and macros used internally by
+// Google Test. They are subject to change without notice.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_OS_LINUX
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif // GTEST_OS_LINUX
+
+#include <ctype.h>
+#include <string.h>
+#include <iomanip>
+#include <limits>
+#include <set>
+
+#include <gtest/internal/gtest-string.h>
+#include <gtest/internal/gtest-filepath.h>
+#include <gtest/internal/gtest-type-util.h>
+
+// Due to C++ preprocessor weirdness, we need double indirection to
+// concatenate two tokens when one of them is __LINE__. Writing
+//
+// foo ## __LINE__
+//
+// will result in the token foo__LINE__, instead of foo followed by
+// the current line number. For more details, see
+// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
+#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
+#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+
+// Google Test defines the testing::Message class to allow construction of
+// test messages via the << operator. The idea is that anything
+// streamable to std::ostream can be streamed to a testing::Message.
+// This allows a user to use his own types in Google Test assertions by
+// overloading the << operator.
+//
+// util/gtl/stl_logging-inl.h overloads << for STL containers. These
+// overloads cannot be defined in the std namespace, as that will be
+// undefined behavior. Therefore, they are defined in the global
+// namespace instead.
+//
+// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
+// overloads are visible in either the std namespace or the global
+// namespace, but not other namespaces, including the testing
+// namespace which Google Test's Message class is in.
+//
+// To allow STL containers (and other types that has a << operator
+// defined in the global namespace) to be used in Google Test assertions,
+// testing::Message must access the custom << operator from the global
+// namespace. Hence this helper function.
+//
+// Note: Jeffrey Yasskin suggested an alternative fix by "using
+// ::operator<<;" in the definition of Message's operator<<. That fix
+// doesn't require a helper function, but unfortunately doesn't
+// compile with MSVC.
+template <typename T>
+inline void GTestStreamToHelper(std::ostream* os, const T& val) {
+ *os << val;
+}
+
+namespace testing {
+
+// Forward declaration of classes.
+
+class AssertionResult; // Result of an assertion.
+class Message; // Represents a failure message.
+class Test; // Represents a test.
+class TestInfo; // Information about a test.
+class TestPartResult; // Result of a test part.
+class UnitTest; // A collection of test cases.
+
+namespace internal {
+
+struct TraceInfo; // Information about a trace point.
+class ScopedTrace; // Implements scoped trace.
+class TestInfoImpl; // Opaque implementation of TestInfo
+class UnitTestImpl; // Opaque implementation of UnitTest
+
+// How many times InitGoogleTest() has been called.
+extern int g_init_gtest_count;
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+GTEST_API_ extern const char kStackTraceMarker[];
+
+// A secret type that Google Test users don't know about. It has no
+// definition on purpose. Therefore it's impossible to create a
+// Secret object, which is what we want.
+class Secret;
+
+// Two overloaded helpers for checking at compile time whether an
+// expression is a null pointer literal (i.e. NULL or any 0-valued
+// compile-time integral constant). Their return values have
+// different sizes, so we can use sizeof() to test which version is
+// picked by the compiler. These helpers have no implementations, as
+// we only need their signatures.
+//
+// Given IsNullLiteralHelper(x), the compiler will pick the first
+// version if x can be implicitly converted to Secret*, and pick the
+// second version otherwise. Since Secret is a secret and incomplete
+// type, the only expression a user can write that has type Secret* is
+// a null pointer literal. Therefore, we know that x is a null
+// pointer literal if and only if the first version is picked by the
+// compiler.
+char IsNullLiteralHelper(Secret* p);
+char (&IsNullLiteralHelper(...))[2]; // NOLINT
+
+// A compile-time bool constant that is true if and only if x is a
+// null pointer literal (i.e. NULL or any 0-valued compile-time
+// integral constant).
+#ifdef GTEST_ELLIPSIS_NEEDS_POD_
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+#define GTEST_IS_NULL_LITERAL_(x) false
+#else
+#define GTEST_IS_NULL_LITERAL_(x) \
+ (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
+#endif // GTEST_ELLIPSIS_NEEDS_POD_
+
+// Appends the user-supplied message to the Google-Test-generated message.
+GTEST_API_ String AppendUserMessage(const String& gtest_msg,
+ const Message& user_msg);
+
+// A helper class for creating scoped traces in user programs.
+class GTEST_API_ ScopedTrace {
+ public:
+ // The c'tor pushes the given source file location and message onto
+ // a trace stack maintained by Google Test.
+ ScopedTrace(const char* file, int line, const Message& message);
+
+ // The d'tor pops the info pushed by the c'tor.
+ //
+ // Note that the d'tor is not virtual in order to be efficient.
+ // Don't inherit from ScopedTrace!
+ ~ScopedTrace();
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
+} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
+ // c'tor and d'tor. Therefore it doesn't
+ // need to be used otherwise.
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+// Formats a value to be used in a failure message.
+
+#ifdef GTEST_NEEDS_IS_POINTER_
+
+// These are needed as the Nokia Symbian and IBM XL C/C++ compilers
+// cannot decide between const T& and const T* in a function template.
+// These compilers _can_ decide between class template specializations
+// for T and T*, so a tr1::type_traits-like is_pointer works, and we
+// can overload on that.
+
+// This overload makes sure that all pointers (including
+// those to char or wchar_t) are printed as raw pointers.
+template <typename T>
+inline String FormatValueForFailureMessage(internal::true_type /*dummy*/,
+ T* pointer) {
+ return StreamableToString(static_cast<const void*>(pointer));
+}
+
+template <typename T>
+inline String FormatValueForFailureMessage(internal::false_type /*dummy*/,
+ const T& value) {
+ return StreamableToString(value);
+}
+
+template <typename T>
+inline String FormatForFailureMessage(const T& value) {
+ return FormatValueForFailureMessage(
+ typename internal::is_pointer<T>::type(), value);
+}
+
+#else
+
+// These are needed as the above solution using is_pointer has the
+// limitation that T cannot be a type without external linkage, when
+// compiled using MSVC.
+
+template <typename T>
+inline String FormatForFailureMessage(const T& value) {
+ return StreamableToString(value);
+}
+
+// This overload makes sure that all pointers (including
+// those to char or wchar_t) are printed as raw pointers.
+template <typename T>
+inline String FormatForFailureMessage(T* pointer) {
+ return StreamableToString(static_cast<const void*>(pointer));
+}
+
+#endif // GTEST_NEEDS_IS_POINTER_
+
+// These overloaded versions handle narrow and wide characters.
+GTEST_API_ String FormatForFailureMessage(char ch);
+GTEST_API_ String FormatForFailureMessage(wchar_t wchar);
+
+// When this operand is a const char* or char*, and the other operand
+// is a ::std::string or ::string, we print this operand as a C string
+// rather than a pointer. We do the same for wide strings.
+
+// This internal macro is used to avoid duplicated code.
+#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\
+inline String FormatForComparisonFailureMessage(\
+ operand2_type::value_type* str, const operand2_type& /*operand2*/) {\
+ return operand1_printer(str);\
+}\
+inline String FormatForComparisonFailureMessage(\
+ const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\
+ return operand1_printer(str);\
+}
+
+GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)
+#if GTEST_HAS_STD_WSTRING
+GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)
+#endif // GTEST_HAS_GLOBAL_STRING
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+#undef GTEST_FORMAT_IMPL_
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const String& expected_value,
+ const String& actual_value,
+ bool ignoring_case);
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+GTEST_API_ String GetBoolAssertionFailureMessage(
+ const AssertionResult& assertion_result,
+ const char* expression_text,
+ const char* actual_predicate_value,
+ const char* expected_predicate_value);
+
+// This template class represents an IEEE floating-point number
+// (either single-precision or double-precision, depending on the
+// template parameters).
+//
+// The purpose of this class is to do more sophisticated number
+// comparison. (Due to round-off error, etc, it's very unlikely that
+// two floating-points will be equal exactly. Hence a naive
+// comparison by the == operation often doesn't work.)
+//
+// Format of IEEE floating-point:
+//
+// The most-significant bit being the leftmost, an IEEE
+// floating-point looks like
+//
+// sign_bit exponent_bits fraction_bits
+//
+// Here, sign_bit is a single bit that designates the sign of the
+// number.
+//
+// For float, there are 8 exponent bits and 23 fraction bits.
+//
+// For double, there are 11 exponent bits and 52 fraction bits.
+//
+// More details can be found at
+// http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
+//
+// Template parameter:
+//
+// RawType: the raw floating-point type (either float or double)
+template <typename RawType>
+class FloatingPoint {
+ public:
+ // Defines the unsigned integer type that has the same size as the
+ // floating point number.
+ typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
+
+ // Constants.
+
+ // # of bits in a number.
+ static const size_t kBitCount = 8*sizeof(RawType);
+
+ // # of fraction bits in a number.
+ static const size_t kFractionBitCount =
+ std::numeric_limits<RawType>::digits - 1;
+
+ // # of exponent bits in a number.
+ static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
+
+ // The mask for the sign bit.
+ static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
+
+ // The mask for the fraction bits.
+ static const Bits kFractionBitMask =
+ ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
+
+ // The mask for the exponent bits.
+ static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
+
+ // How many ULP's (Units in the Last Place) we want to tolerate when
+ // comparing two numbers. The larger the value, the more error we
+ // allow. A 0 value means that two numbers must be exactly the same
+ // to be considered equal.
+ //
+ // The maximum error of a single floating-point operation is 0.5
+ // units in the last place. On Intel CPU's, all floating-point
+ // calculations are done with 80-bit precision, while double has 64
+ // bits. Therefore, 4 should be enough for ordinary use.
+ //
+ // See the following article for more details on ULP:
+ // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
+ static const size_t kMaxUlps = 4;
+
+ // Constructs a FloatingPoint from a raw floating-point number.
+ //
+ // On an Intel CPU, passing a non-normalized NAN (Not a Number)
+ // around may change its bits, although the new value is guaranteed
+ // to be also a NAN. Therefore, don't expect this constructor to
+ // preserve the bits in x when x is a NAN.
+ explicit FloatingPoint(const RawType& x) { u_.value_ = x; }
+
+ // Static methods
+
+ // Reinterprets a bit pattern as a floating-point number.
+ //
+ // This function is needed to test the AlmostEquals() method.
+ static RawType ReinterpretBits(const Bits bits) {
+ FloatingPoint fp(0);
+ fp.u_.bits_ = bits;
+ return fp.u_.value_;
+ }
+
+ // Returns the floating-point number that represent positive infinity.
+ static RawType Infinity() {
+ return ReinterpretBits(kExponentBitMask);
+ }
+
+ // Non-static methods
+
+ // Returns the bits that represents this number.
+ const Bits &bits() const { return u_.bits_; }
+
+ // Returns the exponent bits of this number.
+ Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }
+
+ // Returns the fraction bits of this number.
+ Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }
+
+ // Returns the sign bit of this number.
+ Bits sign_bit() const { return kSignBitMask & u_.bits_; }
+
+ // Returns true iff this is NAN (not a number).
+ bool is_nan() const {
+ // It's a NAN if the exponent bits are all ones and the fraction
+ // bits are not entirely zeros.
+ return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
+ }
+
+ // Returns true iff this number is at most kMaxUlps ULP's away from
+ // rhs. In particular, this function:
+ //
+ // - returns false if either number is (or both are) NAN.
+ // - treats really large numbers as almost equal to infinity.
+ // - thinks +0.0 and -0.0 are 0 DLP's apart.
+ bool AlmostEquals(const FloatingPoint& rhs) const {
+ // The IEEE standard says that any comparison operation involving
+ // a NAN must return false.
+ if (is_nan() || rhs.is_nan()) return false;
+
+ return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
+ <= kMaxUlps;
+ }
+
+ private:
+ // The data type used to store the actual floating-point number.
+ union FloatingPointUnion {
+ RawType value_; // The raw floating-point number.
+ Bits bits_; // The bits that represent the number.
+ };
+
+ // Converts an integer from the sign-and-magnitude representation to
+ // the biased representation. More precisely, let N be 2 to the
+ // power of (kBitCount - 1), an integer x is represented by the
+ // unsigned number x + N.
+ //
+ // For instance,
+ //
+ // -N + 1 (the most negative number representable using
+ // sign-and-magnitude) is represented by 1;
+ // 0 is represented by N; and
+ // N - 1 (the biggest number representable using
+ // sign-and-magnitude) is represented by 2N - 1.
+ //
+ // Read http://en.wikipedia.org/wiki/Signed_number_representations
+ // for more details on signed number representations.
+ static Bits SignAndMagnitudeToBiased(const Bits &sam) {
+ if (kSignBitMask & sam) {
+ // sam represents a negative number.
+ return ~sam + 1;
+ } else {
+ // sam represents a positive number.
+ return kSignBitMask | sam;
+ }
+ }
+
+ // Given two numbers in the sign-and-magnitude representation,
+ // returns the distance between them as an unsigned number.
+ static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
+ const Bits &sam2) {
+ const Bits biased1 = SignAndMagnitudeToBiased(sam1);
+ const Bits biased2 = SignAndMagnitudeToBiased(sam2);
+ return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
+ }
+
+ FloatingPointUnion u_;
+};
+
+// Typedefs the instances of the FloatingPoint template class that we
+// care to use.
+typedef FloatingPoint<float> Float;
+typedef FloatingPoint<double> Double;
+
+// In order to catch the mistake of putting tests that use different
+// test fixture classes in the same test case, we need to assign
+// unique IDs to fixture classes and compare them. The TypeId type is
+// used to hold such IDs. The user should treat TypeId as an opaque
+// type: the only operation allowed on TypeId values is to compare
+// them for equality using the == operator.
+typedef const void* TypeId;
+
+template <typename T>
+class TypeIdHelper {
+ public:
+ // dummy_ must not have a const type. Otherwise an overly eager
+ // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
+ // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
+ static bool dummy_;
+};
+
+template <typename T>
+bool TypeIdHelper<T>::dummy_ = false;
+
+// GetTypeId<T>() returns the ID of type T. Different values will be
+// returned for different types. Calling the function twice with the
+// same type argument is guaranteed to return the same ID.
+template <typename T>
+TypeId GetTypeId() {
+ // The compiler is required to allocate a different
+ // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
+ // the template. Therefore, the address of dummy_ is guaranteed to
+ // be unique.
+ return &(TypeIdHelper<T>::dummy_);
+}
+
+// Returns the type ID of ::testing::Test. Always call this instead
+// of GetTypeId< ::testing::Test>() to get the type ID of
+// ::testing::Test, as the latter may give the wrong result due to a
+// suspected linker bug when compiling Google Test as a Mac OS X
+// framework.
+GTEST_API_ TypeId GetTestTypeId();
+
+// Defines the abstract factory interface that creates instances
+// of a Test object.
+class TestFactoryBase {
+ public:
+ virtual ~TestFactoryBase() {}
+
+ // Creates a test instance to run. The instance is both created and destroyed
+ // within TestInfoImpl::Run()
+ virtual Test* CreateTest() = 0;
+
+ protected:
+ TestFactoryBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
+};
+
+// This class provides implementation of TeastFactoryBase interface.
+// It is used in TEST and TEST_F macros.
+template <class TestClass>
+class TestFactoryImpl : public TestFactoryBase {
+ public:
+ virtual Test* CreateTest() { return new TestClass; }
+};
+
+#if GTEST_OS_WINDOWS
+
+// Predicate-formatters for implementing the HRESULT checking macros
+// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
+// We pass a long instead of HRESULT to avoid causing an
+// include dependency for the HRESULT type.
+GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr,
+ long hr); // NOLINT
+GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
+ long hr); // NOLINT
+
+#endif // GTEST_OS_WINDOWS
+
+// Formats a source file path and a line number as they would appear
+// in a compiler error message.
+inline String FormatFileLocation(const char* file, int line) {
+ const char* const file_name = file == NULL ? "unknown file" : file;
+ if (line < 0) {
+ return String::Format("%s:", file_name);
+ }
+#ifdef _MSC_VER
+ return String::Format("%s(%d):", file_name, line);
+#else
+ return String::Format("%s:%d:", file_name, line);
+#endif // _MSC_VER
+}
+
+// Types of SetUpTestCase() and TearDownTestCase() functions.
+typedef void (*SetUpTestCaseFunc)();
+typedef void (*TearDownTestCaseFunc)();
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// test_case_comment: a comment on the test case that will be included in
+// the test output
+// comment: a comment on the test that will be included in the
+// test output
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory);
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false. None of pstr, *pstr, and prefix can be NULL.
+bool SkipPrefix(const char* prefix, const char** pstr);
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// State of the definition of a type-parameterized test case.
+class GTEST_API_ TypedTestCasePState {
+ public:
+ TypedTestCasePState() : registered_(false) {}
+
+ // Adds the given test name to defined_test_names_ and return true
+ // if the test case hasn't been registered; otherwise aborts the
+ // program.
+ bool AddTestName(const char* file, int line, const char* case_name,
+ const char* test_name) {
+ if (registered_) {
+ fprintf(stderr, "%s Test %s must be defined before "
+ "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
+ FormatFileLocation(file, line).c_str(), test_name, case_name);
+ fflush(stderr);
+ posix::Abort();
+ }
+ defined_test_names_.insert(test_name);
+ return true;
+ }
+
+ // Verifies that registered_tests match the test names in
+ // defined_test_names_; returns registered_tests if successful, or
+ // aborts the program otherwise.
+ const char* VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests);
+
+ private:
+ bool registered_;
+ ::std::set<const char*> defined_test_names_;
+};
+
+// Skips to the first non-space char after the first comma in 'str';
+// returns NULL if no comma is found in 'str'.
+inline const char* SkipComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ if (comma == NULL) {
+ return NULL;
+ }
+ while (isspace(*(++comma))) {}
+ return comma;
+}
+
+// Returns the prefix of 'str' before the first comma in it; returns
+// the entire string if it contains no comma.
+inline String GetPrefixUntilComma(const char* str) {
+ const char* comma = strchr(str, ',');
+ return comma == NULL ? String(str) : String(str, comma - str);
+}
+
+// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
+// registers a list of type-parameterized tests with Google Test. The
+// return value is insignificant - we just need to return something
+// such that we can call this function in a namespace scope.
+//
+// Implementation note: The GTEST_TEMPLATE_ macro declares a template
+// template parameter. It's defined in gtest-type-util.h.
+template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
+class TypeParameterizedTest {
+ public:
+ // 'index' is the index of the test in the type list 'Types'
+ // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
+ // Types). Valid values for 'index' are [0, N - 1] where N is the
+ // length of Types.
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names, int index) {
+ typedef typename Types::Head Type;
+ typedef Fixture<Type> FixtureClass;
+ typedef typename GTEST_BIND_(TestSel, Type) TestClass;
+
+ // First, registers the first type-parameterized test in the type
+ // list.
+ MakeAndRegisterTestInfo(
+ String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/",
+ case_name, index).c_str(),
+ GetPrefixUntilComma(test_names).c_str(),
+ String::Format("TypeParam = %s", GetTypeName<Type>().c_str()).c_str(),
+ "",
+ GetTypeId<FixtureClass>(),
+ TestClass::SetUpTestCase,
+ TestClass::TearDownTestCase,
+ new TestFactoryImpl<TestClass>);
+
+ // Next, recurses (at compile time) with the tail of the type list.
+ return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
+ ::Register(prefix, case_name, test_names, index + 1);
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, class TestSel>
+class TypeParameterizedTest<Fixture, TestSel, Types0> {
+ public:
+ static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+ const char* /*test_names*/, int /*index*/) {
+ return true;
+ }
+};
+
+// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
+// registers *all combinations* of 'Tests' and 'Types' with Google
+// Test. The return value is insignificant - we just need to return
+// something such that we can call this function in a namespace scope.
+template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
+class TypeParameterizedTestCase {
+ public:
+ static bool Register(const char* prefix, const char* case_name,
+ const char* test_names) {
+ typedef typename Tests::Head Head;
+
+ // First, register the first test in 'Test' for each type in 'Types'.
+ TypeParameterizedTest<Fixture, Head, Types>::Register(
+ prefix, case_name, test_names, 0);
+
+ // Next, recurses (at compile time) with the tail of the test list.
+ return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
+ ::Register(prefix, case_name, SkipComma(test_names));
+ }
+};
+
+// The base case for the compile time recursion.
+template <GTEST_TEMPLATE_ Fixture, typename Types>
+class TypeParameterizedTestCase<Fixture, Templates0, Types> {
+ public:
+ static bool Register(const char* /*prefix*/, const char* /*case_name*/,
+ const char* /*test_names*/) {
+ return true;
+ }
+};
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test,
+ int skip_count);
+
+// Helpers for suppressing warnings on unreachable code or constant
+// condition.
+
+// Always returns true.
+GTEST_API_ bool AlwaysTrue();
+
+// Always returns false.
+inline bool AlwaysFalse() { return !AlwaysTrue(); }
+
+// A simple Linear Congruential Generator for generating random
+// numbers with a uniform distribution. Unlike rand() and srand(), it
+// doesn't use global state (and therefore can't interfere with user
+// code). Unlike rand_r(), it's portable. An LCG isn't very random,
+// but it's good enough for our purposes.
+class GTEST_API_ Random {
+ public:
+ static const UInt32 kMaxRange = 1u << 31;
+
+ explicit Random(UInt32 seed) : state_(seed) {}
+
+ void Reseed(UInt32 seed) { state_ = seed; }
+
+ // Generates a random number from [0, range). Crashes if 'range' is
+ // 0 or greater than kMaxRange.
+ UInt32 Generate(UInt32 range);
+
+ private:
+ UInt32 state_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
+};
+
+} // namespace internal
+} // namespace testing
+
+#define GTEST_MESSAGE_(message, result_type) \
+ ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \
+ = ::testing::Message()
+
+#define GTEST_FATAL_FAILURE_(message) \
+ return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)
+
+#define GTEST_NONFATAL_FAILURE_(message) \
+ GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
+
+#define GTEST_SUCCESS_(message) \
+ GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
+
+// Suppresses MSVC warnings 4072 (unreachable code) for the code following
+// statement if it returns or throws (or doesn't return or throw in some
+// situations).
+#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
+ if (::testing::internal::AlwaysTrue()) { statement; }
+
+#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const char* gtest_msg = "") { \
+ bool gtest_caught_expected = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (expected_exception const&) { \
+ gtest_caught_expected = true; \
+ } \
+ catch (...) { \
+ gtest_msg = "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws a different " \
+ "type."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ if (!gtest_caught_expected) { \
+ gtest_msg = "Expected: " #statement " throws an exception of type " \
+ #expected_exception ".\n Actual: it throws nothing."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
+ fail(gtest_msg)
+
+#define GTEST_TEST_NO_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const char* gtest_msg = "") { \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (...) { \
+ gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \
+ " Actual: it throws."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
+ fail(gtest_msg)
+
+#define GTEST_TEST_ANY_THROW_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const char* gtest_msg = "") { \
+ bool gtest_caught_any = false; \
+ try { \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ } \
+ catch (...) { \
+ gtest_caught_any = true; \
+ } \
+ if (!gtest_caught_any) { \
+ gtest_msg = "Expected: " #statement " throws an exception.\n" \
+ " Actual: it doesn't."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
+ fail(gtest_msg)
+
+
+// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
+// either a boolean expression or an AssertionResult. text is a textual
+// represenation of expression as it was passed into the EXPECT_TRUE.
+#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const ::testing::AssertionResult gtest_ar_ = \
+ ::testing::AssertionResult(expression)) \
+ ; \
+ else \
+ fail(::testing::internal::GetBoolAssertionFailureMessage(\
+ gtest_ar_, text, #actual, #expected).c_str())
+
+#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (const char* gtest_msg = "") { \
+ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
+ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
+ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
+ gtest_msg = "Expected: " #statement " doesn't generate new fatal " \
+ "failures in the current thread.\n" \
+ " Actual: it does."; \
+ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
+ } \
+ } else \
+ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
+ fail(gtest_msg)
+
+// Expands to the name of the class that implements the given test.
+#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
+ test_case_name##_##test_name##_Test
+
+// Helper macro for defining tests.
+#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
+ public:\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
+ private:\
+ virtual void TestBody();\
+ static ::testing::TestInfo* const test_info_;\
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
+};\
+\
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
+ ::test_info_ =\
+ ::testing::internal::MakeAndRegisterTestInfo(\
+ #test_case_name, #test_name, "", "", \
+ (parent_id), \
+ parent_class::SetUpTestCase, \
+ parent_class::TearDownTestCase, \
+ new ::testing::internal::TestFactoryImpl<\
+ GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-linked_ptr.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-linked_ptr.h
new file mode 100644
index 000000000..540ef4cd4
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-linked_ptr.h
@@ -0,0 +1,242 @@
+// Copyright 2003 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Dan Egnor (egnor@google.com)
+//
+// A "smart" pointer type with reference tracking. Every pointer to a
+// particular object is kept on a circular linked list. When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is assigned, the entire list of pointers to that
+// object is traversed. This class is therefore NOT SUITABLE when there
+// will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+// will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Bill Gibbons suggested we use something like this.
+//
+// Thread Safety:
+// Unlike other linked_ptr implementations, in this implementation
+// a linked_ptr object is thread-safe in the sense that:
+// - it's safe to copy linked_ptr objects concurrently,
+// - it's safe to copy *from* a linked_ptr and read its underlying
+// raw pointer (e.g. via get()) concurrently, and
+// - it's safe to write to two linked_ptrs that point to the same
+// shared object concurrently.
+// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
+// confusion with normal linked_ptr.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <gtest/internal/gtest-port.h>
+
+namespace testing {
+namespace internal {
+
+// Protects copying of all linked_ptr objects.
+GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// This is used internally by all instances of linked_ptr<>. It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+ // Create a new circle that includes only this instance.
+ void join_new() {
+ next_ = this;
+ }
+
+ // Many linked_ptr operations may change p.link_ for some linked_ptr
+ // variable p in the same circle as this object. Therefore we need
+ // to prevent two such operations from occurring concurrently.
+ //
+ // Note that different types of linked_ptr objects can coexist in a
+ // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
+ // linked_ptr<Derived2>). Therefore we must use a single mutex to
+ // protect all linked_ptr objects. This can create serious
+ // contention in production code, but is acceptable in a testing
+ // framework.
+
+ // Join an existing circle.
+ // L < g_linked_ptr_mutex
+ void join(linked_ptr_internal const* ptr) {
+ MutexLock lock(&g_linked_ptr_mutex);
+
+ linked_ptr_internal const* p = ptr;
+ while (p->next_ != ptr) p = p->next_;
+ p->next_ = this;
+ next_ = ptr;
+ }
+
+ // Leave whatever circle we're part of. Returns true if we were the
+ // last member of the circle. Once this is done, you can join() another.
+ // L < g_linked_ptr_mutex
+ bool depart() {
+ MutexLock lock(&g_linked_ptr_mutex);
+
+ if (next_ == this) return true;
+ linked_ptr_internal const* p = next_;
+ while (p->next_ != this) p = p->next_;
+ p->next_ = next_;
+ return false;
+ }
+
+ private:
+ mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+ typedef T element_type;
+
+ // Take over ownership of a raw pointer. This should happen as soon as
+ // possible after the object is created.
+ explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+ ~linked_ptr() { depart(); }
+
+ // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+ template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+ linked_ptr(linked_ptr const& ptr) { // NOLINT
+ assert(&ptr != this);
+ copy(&ptr);
+ }
+
+ // Assignment releases the old value and acquires the new.
+ template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+ depart();
+ copy(&ptr);
+ return *this;
+ }
+
+ linked_ptr& operator=(linked_ptr const& ptr) {
+ if (&ptr != this) {
+ depart();
+ copy(&ptr);
+ }
+ return *this;
+ }
+
+ // Smart pointer members.
+ void reset(T* ptr = NULL) {
+ depart();
+ capture(ptr);
+ }
+ T* get() const { return value_; }
+ T* operator->() const { return value_; }
+ T& operator*() const { return *value_; }
+ // Release ownership of the pointed object and returns it.
+ // Sole ownership by this linked_ptr object is required.
+ T* release() {
+ bool last = link_.depart();
+ assert(last);
+ T* v = value_;
+ value_ = NULL;
+ return v;
+ }
+
+ bool operator==(T* p) const { return value_ == p; }
+ bool operator!=(T* p) const { return value_ != p; }
+ template <typename U>
+ bool operator==(linked_ptr<U> const& ptr) const {
+ return value_ == ptr.get();
+ }
+ template <typename U>
+ bool operator!=(linked_ptr<U> const& ptr) const {
+ return value_ != ptr.get();
+ }
+
+ private:
+ template <typename U>
+ friend class linked_ptr;
+
+ T* value_;
+ linked_ptr_internal link_;
+
+ void depart() {
+ if (link_.depart()) delete value_;
+ }
+
+ void capture(T* ptr) {
+ value_ = ptr;
+ link_.join_new();
+ }
+
+ template <typename U> void copy(linked_ptr<U> const* ptr) {
+ value_ = ptr->get();
+ if (value_)
+ link_.join(&ptr->link_);
+ else
+ link_.join_new();
+ }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+ return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+ return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+ return linked_ptr<T>(ptr);
+}
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util-generated.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util-generated.h
new file mode 100644
index 000000000..ab4ab5662
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util-generated.h
@@ -0,0 +1,4820 @@
+// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most 50 arguments in Values,
+// and at most 10 arguments in Combine. Please contact
+// googletestframework@googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at 10.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include <gtest/internal/gtest-param-util.h>
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(
+ ForwardIterator begin, ForwardIterator end);
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container);
+
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+ explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray1& other);
+
+ const T1 v1_;
+};
+
+template <typename T1, typename T2>
+class ValueArray2 {
+ public:
+ ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray2& other);
+
+ const T1 v1_;
+ const T2 v2_;
+};
+
+template <typename T1, typename T2, typename T3>
+class ValueArray3 {
+ public:
+ ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray3& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+class ValueArray4 {
+ public:
+ ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray4& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class ValueArray5 {
+ public:
+ ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray5& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+class ValueArray6 {
+ public:
+ ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray6& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+class ValueArray7 {
+ public:
+ ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray7& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+class ValueArray8 {
+ public:
+ ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
+ T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray8& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+class ValueArray9 {
+ public:
+ ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
+ T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray9& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+class ValueArray10 {
+ public:
+ ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray10& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+class ValueArray11 {
+ public:
+ ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray11& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+class ValueArray12 {
+ public:
+ ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray12& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+class ValueArray13 {
+ public:
+ ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray13& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+class ValueArray14 {
+ public:
+ ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray14& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+class ValueArray15 {
+ public:
+ ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray15& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+class ValueArray16 {
+ public:
+ ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray16& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+class ValueArray17 {
+ public:
+ ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
+ T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray17& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+class ValueArray18 {
+ public:
+ ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray18& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+class ValueArray19 {
+ public:
+ ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray19& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+class ValueArray20 {
+ public:
+ ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray20& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+class ValueArray21 {
+ public:
+ ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray21& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+class ValueArray22 {
+ public:
+ ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray22& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+class ValueArray23 {
+ public:
+ ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_,
+ v23_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray23& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+class ValueArray24 {
+ public:
+ ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray24& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+class ValueArray25 {
+ public:
+ ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
+ T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray25& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+class ValueArray26 {
+ public:
+ ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray26& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+class ValueArray27 {
+ public:
+ ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray27& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+class ValueArray28 {
+ public:
+ ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray28& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+class ValueArray29 {
+ public:
+ ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray29& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+class ValueArray30 {
+ public:
+ ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray30& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+class ValueArray31 {
+ public:
+ ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray31& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+class ValueArray32 {
+ public:
+ ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray32& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+class ValueArray33 {
+ public:
+ ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
+ T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray33& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+class ValueArray34 {
+ public:
+ ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray34& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+class ValueArray35 {
+ public:
+ ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+ v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_,
+ v35_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray35& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+class ValueArray36 {
+ public:
+ ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+ v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray36& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+class ValueArray37 {
+ public:
+ ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+ v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+ v36_(v36), v37_(v37) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray37& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+class ValueArray38 {
+ public:
+ ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray38& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+class ValueArray39 {
+ public:
+ ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray39& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+class ValueArray40 {
+ public:
+ ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+ v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+ v40_(v40) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray40& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+class ValueArray41 {
+ public:
+ ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
+ T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray41& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+class ValueArray42 {
+ public:
+ ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray42& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+class ValueArray43 {
+ public:
+ ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
+ v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
+ v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
+ v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
+ v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
+ v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
+ v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray43& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+class ValueArray44 {
+ public:
+ ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
+ v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
+ v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
+ v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
+ v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
+ v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
+ v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
+ v43_(v43), v44_(v44) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray44& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+class ValueArray45 {
+ public:
+ ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
+ v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
+ v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
+ v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
+ v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
+ v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
+ v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
+ v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray45& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+class ValueArray46 {
+ public:
+ ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
+ v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+ v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray46& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+class ValueArray47 {
+ public:
+ ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
+ v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
+ v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
+ v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
+ v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
+ v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
+ v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
+ v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
+ v47_(v47) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_,
+ v47_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray47& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+class ValueArray48 {
+ public:
+ ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
+ v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
+ v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
+ v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
+ v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
+ v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
+ v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
+ v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
+ v46_(v46), v47_(v47), v48_(v48) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray48& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+class ValueArray49 {
+ public:
+ ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
+ T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+ v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_, v49_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray49& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+ const T49 v49_;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+class ValueArray50 {
+ public:
+ ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
+ T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
+ T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
+ T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
+ T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
+ T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
+ T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
+ v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
+ v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
+ v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
+ v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
+ v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
+ v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
+ v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
+ v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
+ v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
+ v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
+ v48_, v49_, v50_};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray50& other);
+
+ const T1 v1_;
+ const T2 v2_;
+ const T3 v3_;
+ const T4 v4_;
+ const T5 v5_;
+ const T6 v6_;
+ const T7 v7_;
+ const T8 v8_;
+ const T9 v9_;
+ const T10 v10_;
+ const T11 v11_;
+ const T12 v12_;
+ const T13 v13_;
+ const T14 v14_;
+ const T15 v15_;
+ const T16 v16_;
+ const T17 v17_;
+ const T18 v18_;
+ const T19 v19_;
+ const T20 v20_;
+ const T21 v21_;
+ const T22 v22_;
+ const T23 v23_;
+ const T24 v24_;
+ const T25 v25_;
+ const T26 v26_;
+ const T27 v27_;
+ const T28 v28_;
+ const T29 v29_;
+ const T30 v30_;
+ const T31 v31_;
+ const T32 v32_;
+ const T33 v33_;
+ const T34 v34_;
+ const T35 v35_;
+ const T36 v36_;
+ const T37 v37_;
+ const T38 v38_;
+ const T39 v39_;
+ const T40 v40_;
+ const T41 v41_;
+ const T42 v42_;
+ const T43 v43_;
+ const T44 v44_;
+ const T45 v45_;
+ const T46 v46_;
+ const T47 v47_;
+ const T48 v48_;
+ const T49 v49_;
+ const T50 v50_;
+};
+
+#if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+template <typename T1, typename T2>
+class CartesianProductGenerator2
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2> ParamType;
+
+ CartesianProductGenerator2(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2)
+ : g1_(g1), g2_(g2) {}
+ virtual ~CartesianProductGenerator2() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current2_;
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator2::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator2& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+}; // class CartesianProductGenerator2
+
+
+template <typename T1, typename T2, typename T3>
+class CartesianProductGenerator3
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+
+ CartesianProductGenerator3(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
+ : g1_(g1), g2_(g2), g3_(g3) {}
+ virtual ~CartesianProductGenerator3() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current3_;
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator3::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator3& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+}; // class CartesianProductGenerator3
+
+
+template <typename T1, typename T2, typename T3, typename T4>
+class CartesianProductGenerator4
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+
+ CartesianProductGenerator4(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+ virtual ~CartesianProductGenerator4() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current4_;
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator4::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator4& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+}; // class CartesianProductGenerator4
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+class CartesianProductGenerator5
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+
+ CartesianProductGenerator5(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+ virtual ~CartesianProductGenerator5() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current5_;
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator5::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator5& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+}; // class CartesianProductGenerator5
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+class CartesianProductGenerator6
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+ T6> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+
+ CartesianProductGenerator6(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+ virtual ~CartesianProductGenerator6() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current6_;
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator6::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator6& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+}; // class CartesianProductGenerator6
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+class CartesianProductGenerator7
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+
+ CartesianProductGenerator7(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+ virtual ~CartesianProductGenerator7() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current7_;
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator7::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator7& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+}; // class CartesianProductGenerator7
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+class CartesianProductGenerator8
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+
+ CartesianProductGenerator8(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+ g8_(g8) {}
+ virtual ~CartesianProductGenerator8() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current8_;
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator8::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator8& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+}; // class CartesianProductGenerator8
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+class CartesianProductGenerator9
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8, T9> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+
+ CartesianProductGenerator9(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9) {}
+ virtual ~CartesianProductGenerator9() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end(), g9_, g9_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8,
+ const ParamGenerator<T9>& g9,
+ const typename ParamGenerator<T9>::iterator& current9)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+ begin9_(g9.begin()), end9_(g9.end()), current9_(current9) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current9_;
+ if (current9_ == end9_) {
+ current9_ = begin9_;
+ ++current8_;
+ }
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_ &&
+ current9_ == typed_other->current9_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_),
+ begin9_(other.begin9_),
+ end9_(other.end9_),
+ current9_(other.current9_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_,
+ *current9_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_ ||
+ current9_ == end9_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ const typename ParamGenerator<T9>::iterator begin9_;
+ const typename ParamGenerator<T9>::iterator end9_;
+ typename ParamGenerator<T9>::iterator current9_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator9::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator9& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+ const ParamGenerator<T9> g9_;
+}; // class CartesianProductGenerator9
+
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+class CartesianProductGenerator10
+ : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7, T8, T9, T10> > {
+ public:
+ typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+
+ CartesianProductGenerator10(const ParamGenerator<T1>& g1,
+ const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
+ const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
+ const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
+ const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
+ const ParamGenerator<T10>& g10)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9), g10_(g10) {}
+ virtual ~CartesianProductGenerator10() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
+ g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
+ g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
+ g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
+ g8_.end(), g9_, g9_.end(), g10_, g10_.end());
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base,
+ const ParamGenerator<T1>& g1,
+ const typename ParamGenerator<T1>::iterator& current1,
+ const ParamGenerator<T2>& g2,
+ const typename ParamGenerator<T2>::iterator& current2,
+ const ParamGenerator<T3>& g3,
+ const typename ParamGenerator<T3>::iterator& current3,
+ const ParamGenerator<T4>& g4,
+ const typename ParamGenerator<T4>::iterator& current4,
+ const ParamGenerator<T5>& g5,
+ const typename ParamGenerator<T5>::iterator& current5,
+ const ParamGenerator<T6>& g6,
+ const typename ParamGenerator<T6>::iterator& current6,
+ const ParamGenerator<T7>& g7,
+ const typename ParamGenerator<T7>::iterator& current7,
+ const ParamGenerator<T8>& g8,
+ const typename ParamGenerator<T8>::iterator& current8,
+ const ParamGenerator<T9>& g9,
+ const typename ParamGenerator<T9>::iterator& current9,
+ const ParamGenerator<T10>& g10,
+ const typename ParamGenerator<T10>::iterator& current10)
+ : base_(base),
+ begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
+ begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
+ begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
+ begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
+ begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
+ begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
+ begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
+ begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
+ begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
+ begin10_(g10.begin()), end10_(g10.end()), current10_(current10) {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current10_;
+ if (current10_ == end10_) {
+ current10_ = begin10_;
+ ++current9_;
+ }
+ if (current9_ == end9_) {
+ current9_ = begin9_;
+ ++current8_;
+ }
+ if (current8_ == end8_) {
+ current8_ = begin8_;
+ ++current7_;
+ }
+ if (current7_ == end7_) {
+ current7_ = begin7_;
+ ++current6_;
+ }
+ if (current6_ == end6_) {
+ current6_ = begin6_;
+ ++current5_;
+ }
+ if (current5_ == end5_) {
+ current5_ = begin5_;
+ ++current4_;
+ }
+ if (current4_ == end4_) {
+ current4_ = begin4_;
+ ++current3_;
+ }
+ if (current3_ == end3_) {
+ current3_ = begin3_;
+ ++current2_;
+ }
+ if (current2_ == end2_) {
+ current2_ = begin2_;
+ ++current1_;
+ }
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ (
+ current1_ == typed_other->current1_ &&
+ current2_ == typed_other->current2_ &&
+ current3_ == typed_other->current3_ &&
+ current4_ == typed_other->current4_ &&
+ current5_ == typed_other->current5_ &&
+ current6_ == typed_other->current6_ &&
+ current7_ == typed_other->current7_ &&
+ current8_ == typed_other->current8_ &&
+ current9_ == typed_other->current9_ &&
+ current10_ == typed_other->current10_);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_),
+ begin1_(other.begin1_),
+ end1_(other.end1_),
+ current1_(other.current1_),
+ begin2_(other.begin2_),
+ end2_(other.end2_),
+ current2_(other.current2_),
+ begin3_(other.begin3_),
+ end3_(other.end3_),
+ current3_(other.current3_),
+ begin4_(other.begin4_),
+ end4_(other.end4_),
+ current4_(other.current4_),
+ begin5_(other.begin5_),
+ end5_(other.end5_),
+ current5_(other.current5_),
+ begin6_(other.begin6_),
+ end6_(other.end6_),
+ current6_(other.current6_),
+ begin7_(other.begin7_),
+ end7_(other.end7_),
+ current7_(other.current7_),
+ begin8_(other.begin8_),
+ end8_(other.end8_),
+ current8_(other.current8_),
+ begin9_(other.begin9_),
+ end9_(other.end9_),
+ current9_(other.current9_),
+ begin10_(other.begin10_),
+ end10_(other.end10_),
+ current10_(other.current10_) {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType(*current1_, *current2_, *current3_,
+ *current4_, *current5_, *current6_, *current7_, *current8_,
+ *current9_, *current10_);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+ current1_ == end1_ ||
+ current2_ == end2_ ||
+ current3_ == end3_ ||
+ current4_ == end4_ ||
+ current5_ == end5_ ||
+ current6_ == end6_ ||
+ current7_ == end7_ ||
+ current8_ == end8_ ||
+ current9_ == end9_ ||
+ current10_ == end10_;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+ const typename ParamGenerator<T1>::iterator begin1_;
+ const typename ParamGenerator<T1>::iterator end1_;
+ typename ParamGenerator<T1>::iterator current1_;
+ const typename ParamGenerator<T2>::iterator begin2_;
+ const typename ParamGenerator<T2>::iterator end2_;
+ typename ParamGenerator<T2>::iterator current2_;
+ const typename ParamGenerator<T3>::iterator begin3_;
+ const typename ParamGenerator<T3>::iterator end3_;
+ typename ParamGenerator<T3>::iterator current3_;
+ const typename ParamGenerator<T4>::iterator begin4_;
+ const typename ParamGenerator<T4>::iterator end4_;
+ typename ParamGenerator<T4>::iterator current4_;
+ const typename ParamGenerator<T5>::iterator begin5_;
+ const typename ParamGenerator<T5>::iterator end5_;
+ typename ParamGenerator<T5>::iterator current5_;
+ const typename ParamGenerator<T6>::iterator begin6_;
+ const typename ParamGenerator<T6>::iterator end6_;
+ typename ParamGenerator<T6>::iterator current6_;
+ const typename ParamGenerator<T7>::iterator begin7_;
+ const typename ParamGenerator<T7>::iterator end7_;
+ typename ParamGenerator<T7>::iterator current7_;
+ const typename ParamGenerator<T8>::iterator begin8_;
+ const typename ParamGenerator<T8>::iterator end8_;
+ typename ParamGenerator<T8>::iterator current8_;
+ const typename ParamGenerator<T9>::iterator begin9_;
+ const typename ParamGenerator<T9>::iterator end9_;
+ typename ParamGenerator<T9>::iterator current9_;
+ const typename ParamGenerator<T10>::iterator begin10_;
+ const typename ParamGenerator<T10>::iterator end10_;
+ typename ParamGenerator<T10>::iterator current10_;
+ ParamType current_value_;
+ }; // class CartesianProductGenerator10::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator10& other);
+
+ const ParamGenerator<T1> g1_;
+ const ParamGenerator<T2> g2_;
+ const ParamGenerator<T3> g3_;
+ const ParamGenerator<T4> g4_;
+ const ParamGenerator<T5> g5_;
+ const ParamGenerator<T6> g6_;
+ const ParamGenerator<T7> g7_;
+ const ParamGenerator<T8> g8_;
+ const ParamGenerator<T9> g9_;
+ const ParamGenerator<T10> g10_;
+}; // class CartesianProductGenerator10
+
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+template <class Generator1, class Generator2>
+class CartesianProductHolder2 {
+ public:
+CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
+ : g1_(g1), g2_(g2) {}
+ template <typename T1, typename T2>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+ new CartesianProductGenerator2<T1, T2>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder2& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+}; // class CartesianProductHolder2
+
+template <class Generator1, class Generator2, class Generator3>
+class CartesianProductHolder3 {
+ public:
+CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3)
+ : g1_(g1), g2_(g2), g3_(g3) {}
+ template <typename T1, typename T2, typename T3>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+ new CartesianProductGenerator3<T1, T2, T3>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder3& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+}; // class CartesianProductHolder3
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4>
+class CartesianProductHolder4 {
+ public:
+CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
+ template <typename T1, typename T2, typename T3, typename T4>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+ new CartesianProductGenerator4<T1, T2, T3, T4>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder4& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+}; // class CartesianProductHolder4
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5>
+class CartesianProductHolder5 {
+ public:
+CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+ new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder5& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+}; // class CartesianProductHolder5
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6>
+class CartesianProductHolder6 {
+ public:
+CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+ new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder6& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+}; // class CartesianProductHolder6
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7>
+class CartesianProductHolder7 {
+ public:
+CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+ T7> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+ new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder7& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+}; // class CartesianProductHolder7
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8>
+class CartesianProductHolder8 {
+ public:
+CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
+ g8_(g8) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+ T8> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+ new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder8& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+}; // class CartesianProductHolder8
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8, class Generator9>
+class CartesianProductHolder9 {
+ public:
+CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8,
+ const Generator9& g9)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9> >(
+ new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_),
+ static_cast<ParamGenerator<T9> >(g9_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder9& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+ const Generator9 g9_;
+}; // class CartesianProductHolder9
+
+template <class Generator1, class Generator2, class Generator3,
+ class Generator4, class Generator5, class Generator6, class Generator7,
+ class Generator8, class Generator9, class Generator10>
+class CartesianProductHolder10 {
+ public:
+CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
+ const Generator3& g3, const Generator4& g4, const Generator5& g5,
+ const Generator6& g6, const Generator7& g7, const Generator8& g8,
+ const Generator9& g9, const Generator10& g10)
+ : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
+ g9_(g9), g10_(g10) {}
+ template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+ operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9, T10> >() const {
+ return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+ T9, T10> >(
+ new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+ T10>(
+ static_cast<ParamGenerator<T1> >(g1_),
+ static_cast<ParamGenerator<T2> >(g2_),
+ static_cast<ParamGenerator<T3> >(g3_),
+ static_cast<ParamGenerator<T4> >(g4_),
+ static_cast<ParamGenerator<T5> >(g5_),
+ static_cast<ParamGenerator<T6> >(g6_),
+ static_cast<ParamGenerator<T7> >(g7_),
+ static_cast<ParamGenerator<T8> >(g8_),
+ static_cast<ParamGenerator<T9> >(g9_),
+ static_cast<ParamGenerator<T10> >(g10_)));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder10& other);
+
+ const Generator1 g1_;
+ const Generator2 g2_;
+ const Generator3 g3_;
+ const Generator4 g4_;
+ const Generator5 g5_;
+ const Generator6 g6_;
+ const Generator7 g7_;
+ const Generator8 g8_;
+ const Generator9 g9_;
+ const Generator10 g10_;
+}; // class CartesianProductHolder10
+
+#endif // GTEST_HAS_COMBINE
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util-generated.h.pump b/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util-generated.h.pump
new file mode 100644
index 000000000..baedfbc2d
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util-generated.h.pump
@@ -0,0 +1,301 @@
+$$ -*- mode: c++; -*-
+$var n = 50 $$ Maximum length of Values arguments we want to support.
+$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently Google Test supports at most $n arguments in Values,
+// and at most $maxtuple arguments in Combine. Please contact
+// googletestframework@googlegroups.com if you need more.
+// Please note that the number of arguments to Combine is limited
+// by the maximum arity of the implementation of tr1::tuple which is
+// currently set at $maxtuple.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include <gtest/internal/gtest-param-util.h>
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+
+// Forward declarations of ValuesIn(), which is implemented in
+// include/gtest/gtest-param-test.h.
+template <typename ForwardIterator>
+internal::ParamGenerator<
+ typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(
+ ForwardIterator begin, ForwardIterator end);
+
+template <typename T, size_t N>
+internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
+
+template <class Container>
+internal::ParamGenerator<typename Container::value_type> ValuesIn(
+ const Container& container);
+
+namespace internal {
+
+// Used in the Values() function to provide polymorphic capabilities.
+template <typename T1>
+class ValueArray1 {
+ public:
+ explicit ValueArray1(T1 v1) : v1_(v1) {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray1& other);
+
+ const T1 v1_;
+};
+
+$range i 2..n
+$for i [[
+$range j 1..i
+
+template <$for j, [[typename T$j]]>
+class ValueArray$i {
+ public:
+ ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {}
+
+ template <typename T>
+ operator ParamGenerator<T>() const {
+ const T array[] = {$for j, [[v$(j)_]]};
+ return ValuesIn(array);
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const ValueArray$i& other);
+
+$for j [[
+
+ const T$j v$(j)_;
+]]
+
+};
+
+]]
+
+#if GTEST_HAS_COMBINE
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Generates values from the Cartesian product of values produced
+// by the argument generators.
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+$range k 2..i
+
+template <$for j, [[typename T$j]]>
+class CartesianProductGenerator$i
+ : public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > {
+ public:
+ typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType;
+
+ CartesianProductGenerator$i($for j, [[const ParamGenerator<T$j>& g$j]])
+ : $for j, [[g$(j)_(g$j)]] {}
+ virtual ~CartesianProductGenerator$i() {}
+
+ virtual ParamIteratorInterface<ParamType>* Begin() const {
+ return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]);
+ }
+ virtual ParamIteratorInterface<ParamType>* End() const {
+ return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]);
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<ParamType> {
+ public:
+ Iterator(const ParamGeneratorInterface<ParamType>* base, $for j, [[
+
+ const ParamGenerator<T$j>& g$j,
+ const typename ParamGenerator<T$j>::iterator& current$(j)]])
+ : base_(base),
+$for j, [[
+
+ begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j)
+]] {
+ ComputeCurrentValue();
+ }
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
+ return base_;
+ }
+ // Advance should not be called on beyond-of-range iterators
+ // so no component iterators must be beyond end of range, either.
+ virtual void Advance() {
+ assert(!AtEnd());
+ ++current$(i)_;
+
+$for k [[
+ if (current$(i+2-k)_ == end$(i+2-k)_) {
+ current$(i+2-k)_ = begin$(i+2-k)_;
+ ++current$(i+2-k-1)_;
+ }
+
+]]
+ ComputeCurrentValue();
+ }
+ virtual ParamIteratorInterface<ParamType>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const ParamType* Current() const { return &current_value_; }
+ virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const Iterator* typed_other =
+ CheckedDowncastToActualType<const Iterator>(&other);
+ // We must report iterators equal if they both point beyond their
+ // respective ranges. That can happen in a variety of fashions,
+ // so we have to consult AtEnd().
+ return (AtEnd() && typed_other->AtEnd()) ||
+ ($for j && [[
+
+ current$(j)_ == typed_other->current$(j)_
+]]);
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : base_(other.base_), $for j, [[
+
+ begin$(j)_(other.begin$(j)_),
+ end$(j)_(other.end$(j)_),
+ current$(j)_(other.current$(j)_)
+]] {
+ ComputeCurrentValue();
+ }
+
+ void ComputeCurrentValue() {
+ if (!AtEnd())
+ current_value_ = ParamType($for j, [[*current$(j)_]]);
+ }
+ bool AtEnd() const {
+ // We must report iterator past the end of the range when either of the
+ // component iterators has reached the end of its range.
+ return
+$for j || [[
+
+ current$(j)_ == end$(j)_
+]];
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<ParamType>* const base_;
+ // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
+ // current[i]_ is the actual traversing iterator.
+$for j [[
+
+ const typename ParamGenerator<T$j>::iterator begin$(j)_;
+ const typename ParamGenerator<T$j>::iterator end$(j)_;
+ typename ParamGenerator<T$j>::iterator current$(j)_;
+]]
+
+ ParamType current_value_;
+ }; // class CartesianProductGenerator$i::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductGenerator$i& other);
+
+
+$for j [[
+ const ParamGenerator<T$j> g$(j)_;
+
+]]
+}; // class CartesianProductGenerator$i
+
+
+]]
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Helper classes providing Combine() with polymorphic features. They allow
+// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
+// convertible to U.
+//
+$range i 2..maxtuple
+$for i [[
+$range j 1..i
+
+template <$for j, [[class Generator$j]]>
+class CartesianProductHolder$i {
+ public:
+CartesianProductHolder$i($for j, [[const Generator$j& g$j]])
+ : $for j, [[g$(j)_(g$j)]] {}
+ template <$for j, [[typename T$j]]>
+ operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const {
+ return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >(
+ new CartesianProductGenerator$i<$for j, [[T$j]]>(
+$for j,[[
+
+ static_cast<ParamGenerator<T$j> >(g$(j)_)
+]]));
+ }
+
+ private:
+ // No implementation - assignment is unsupported.
+ void operator=(const CartesianProductHolder$i& other);
+
+
+$for j [[
+ const Generator$j g$(j)_;
+
+]]
+}; // class CartesianProductHolder$i
+
+]]
+
+#endif // GTEST_HAS_COMBINE
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util.h
new file mode 100644
index 000000000..0cbb58c21
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-param-util.h
@@ -0,0 +1,619 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// Type and function utilities for implementing parameterized tests.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+// scripts/fuse_gtest.py depends on gtest's own header being #included
+// *unconditionally*. Therefore these #includes cannot be moved
+// inside #if GTEST_HAS_PARAM_TEST.
+#include <gtest/internal/gtest-internal.h>
+#include <gtest/internal/gtest-linked_ptr.h>
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace testing {
+namespace internal {
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Outputs a message explaining invalid registration of different
+// fixture class for the same test case. This may happen when
+// TEST_P macro is used to define two tests with the same name
+// but in different namespaces.
+GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
+ const char* file, int line);
+
+template <typename> class ParamGeneratorInterface;
+template <typename> class ParamGenerator;
+
+// Interface for iterating over elements provided by an implementation
+// of ParamGeneratorInterface<T>.
+template <typename T>
+class ParamIteratorInterface {
+ public:
+ virtual ~ParamIteratorInterface() {}
+ // A pointer to the base generator instance.
+ // Used only for the purposes of iterator comparison
+ // to make sure that two iterators belong to the same generator.
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
+ // Advances iterator to point to the next element
+ // provided by the generator. The caller is responsible
+ // for not calling Advance() on an iterator equal to
+ // BaseGenerator()->End().
+ virtual void Advance() = 0;
+ // Clones the iterator object. Used for implementing copy semantics
+ // of ParamIterator<T>.
+ virtual ParamIteratorInterface* Clone() const = 0;
+ // Dereferences the current iterator and provides (read-only) access
+ // to the pointed value. It is the caller's responsibility not to call
+ // Current() on an iterator equal to BaseGenerator()->End().
+ // Used for implementing ParamGenerator<T>::operator*().
+ virtual const T* Current() const = 0;
+ // Determines whether the given iterator and other point to the same
+ // element in the sequence generated by the generator.
+ // Used for implementing ParamGenerator<T>::operator==().
+ virtual bool Equals(const ParamIteratorInterface& other) const = 0;
+};
+
+// Class iterating over elements provided by an implementation of
+// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
+// and implements the const forward iterator concept.
+template <typename T>
+class ParamIterator {
+ public:
+ typedef T value_type;
+ typedef const T& reference;
+ typedef ptrdiff_t difference_type;
+
+ // ParamIterator assumes ownership of the impl_ pointer.
+ ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
+ ParamIterator& operator=(const ParamIterator& other) {
+ if (this != &other)
+ impl_.reset(other.impl_->Clone());
+ return *this;
+ }
+
+ const T& operator*() const { return *impl_->Current(); }
+ const T* operator->() const { return impl_->Current(); }
+ // Prefix version of operator++.
+ ParamIterator& operator++() {
+ impl_->Advance();
+ return *this;
+ }
+ // Postfix version of operator++.
+ ParamIterator operator++(int /*unused*/) {
+ ParamIteratorInterface<T>* clone = impl_->Clone();
+ impl_->Advance();
+ return ParamIterator(clone);
+ }
+ bool operator==(const ParamIterator& other) const {
+ return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
+ }
+ bool operator!=(const ParamIterator& other) const {
+ return !(*this == other);
+ }
+
+ private:
+ friend class ParamGenerator<T>;
+ explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
+ scoped_ptr<ParamIteratorInterface<T> > impl_;
+};
+
+// ParamGeneratorInterface<T> is the binary interface to access generators
+// defined in other translation units.
+template <typename T>
+class ParamGeneratorInterface {
+ public:
+ typedef T ParamType;
+
+ virtual ~ParamGeneratorInterface() {}
+
+ // Generator interface definition
+ virtual ParamIteratorInterface<T>* Begin() const = 0;
+ virtual ParamIteratorInterface<T>* End() const = 0;
+};
+
+// Wraps ParamGeneratorInterface<T> and provides general generator syntax
+// compatible with the STL Container concept.
+// This class implements copy initialization semantics and the contained
+// ParamGeneratorInterface<T> instance is shared among all copies
+// of the original object. This is possible because that instance is immutable.
+template<typename T>
+class ParamGenerator {
+ public:
+ typedef ParamIterator<T> iterator;
+
+ explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
+ ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
+
+ ParamGenerator& operator=(const ParamGenerator& other) {
+ impl_ = other.impl_;
+ return *this;
+ }
+
+ iterator begin() const { return iterator(impl_->Begin()); }
+ iterator end() const { return iterator(impl_->End()); }
+
+ private:
+ ::testing::internal::linked_ptr<const ParamGeneratorInterface<T> > impl_;
+};
+
+// Generates values from a range of two comparable values. Can be used to
+// generate sequences of user-defined types that implement operator+() and
+// operator<().
+// This class is used in the Range() function.
+template <typename T, typename IncrementT>
+class RangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ RangeGenerator(T begin, T end, IncrementT step)
+ : begin_(begin), end_(end),
+ step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
+ virtual ~RangeGenerator() {}
+
+ virtual ParamIteratorInterface<T>* Begin() const {
+ return new Iterator(this, begin_, 0, step_);
+ }
+ virtual ParamIteratorInterface<T>* End() const {
+ return new Iterator(this, end_, end_index_, step_);
+ }
+
+ private:
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
+ IncrementT step)
+ : base_(base), value_(value), index_(index), step_(step) {}
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ return base_;
+ }
+ virtual void Advance() {
+ value_ = value_ + step_;
+ index_++;
+ }
+ virtual ParamIteratorInterface<T>* Clone() const {
+ return new Iterator(*this);
+ }
+ virtual const T* Current() const { return &value_; }
+ virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ const int other_index =
+ CheckedDowncastToActualType<const Iterator>(&other)->index_;
+ return index_ == other_index;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ : ParamIteratorInterface<T>(),
+ base_(other.base_), value_(other.value_), index_(other.index_),
+ step_(other.step_) {}
+
+ // No implementation - assignment is unsupported.
+ void operator=(const Iterator& other);
+
+ const ParamGeneratorInterface<T>* const base_;
+ T value_;
+ int index_;
+ const IncrementT step_;
+ }; // class RangeGenerator::Iterator
+
+ static int CalculateEndIndex(const T& begin,
+ const T& end,
+ const IncrementT& step) {
+ int end_index = 0;
+ for (T i = begin; i < end; i = i + step)
+ end_index++;
+ return end_index;
+ }
+
+ // No implementation - assignment is unsupported.
+ void operator=(const RangeGenerator& other);
+
+ const T begin_;
+ const T end_;
+ const IncrementT step_;
+ // The index for the end() iterator. All the elements in the generated
+ // sequence are indexed (0-based) to aid iterator comparison.
+ const int end_index_;
+}; // class RangeGenerator
+
+
+// Generates values from a pair of STL-style iterators. Used in the
+// ValuesIn() function. The elements are copied from the source range
+// since the source can be located on the stack, and the generator
+// is likely to persist beyond that stack frame.
+template <typename T>
+class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
+ public:
+ template <typename ForwardIterator>
+ ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
+ : container_(begin, end) {}
+ virtual ~ValuesInIteratorRangeGenerator() {}
+
+ virtual ParamIteratorInterface<T>* Begin() const {
+ return new Iterator(this, container_.begin());
+ }
+ virtual ParamIteratorInterface<T>* End() const {
+ return new Iterator(this, container_.end());
+ }
+
+ private:
+ typedef typename ::std::vector<T> ContainerType;
+
+ class Iterator : public ParamIteratorInterface<T> {
+ public:
+ Iterator(const ParamGeneratorInterface<T>* base,
+ typename ContainerType::const_iterator iterator)
+ : base_(base), iterator_(iterator) {}
+ virtual ~Iterator() {}
+
+ virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
+ return base_;
+ }
+ virtual void Advance() {
+ ++iterator_;
+ value_.reset();
+ }
+ virtual ParamIteratorInterface<T>* Clone() const {
+ return new Iterator(*this);
+ }
+ // We need to use cached value referenced by iterator_ because *iterator_
+ // can return a temporary object (and of type other then T), so just
+ // having "return &*iterator_;" doesn't work.
+ // value_ is updated here and not in Advance() because Advance()
+ // can advance iterator_ beyond the end of the range, and we cannot
+ // detect that fact. The client code, on the other hand, is
+ // responsible for not calling Current() on an out-of-range iterator.
+ virtual const T* Current() const {
+ if (value_.get() == NULL)
+ value_.reset(new T(*iterator_));
+ return value_.get();
+ }
+ virtual bool Equals(const ParamIteratorInterface<T>& other) const {
+ // Having the same base generator guarantees that the other
+ // iterator is of the same type and we can downcast.
+ GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
+ << "The program attempted to compare iterators "
+ << "from different generators." << std::endl;
+ return iterator_ ==
+ CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
+ }
+
+ private:
+ Iterator(const Iterator& other)
+ // The explicit constructor call suppresses a false warning
+ // emitted by gcc when supplied with the -Wextra option.
+ : ParamIteratorInterface<T>(),
+ base_(other.base_),
+ iterator_(other.iterator_) {}
+
+ const ParamGeneratorInterface<T>* const base_;
+ typename ContainerType::const_iterator iterator_;
+ // A cached value of *iterator_. We keep it here to allow access by
+ // pointer in the wrapping iterator's operator->().
+ // value_ needs to be mutable to be accessed in Current().
+ // Use of scoped_ptr helps manage cached value's lifetime,
+ // which is bound by the lifespan of the iterator itself.
+ mutable scoped_ptr<const T> value_;
+ }; // class ValuesInIteratorRangeGenerator::Iterator
+
+ // No implementation - assignment is unsupported.
+ void operator=(const ValuesInIteratorRangeGenerator& other);
+
+ const ContainerType container_;
+}; // class ValuesInIteratorRangeGenerator
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Stores a parameter value and later creates tests parameterized with that
+// value.
+template <class TestClass>
+class ParameterizedTestFactory : public TestFactoryBase {
+ public:
+ typedef typename TestClass::ParamType ParamType;
+ explicit ParameterizedTestFactory(ParamType parameter) :
+ parameter_(parameter) {}
+ virtual Test* CreateTest() {
+ TestClass::SetParam(&parameter_);
+ return new TestClass();
+ }
+
+ private:
+ const ParamType parameter_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactoryBase is a base class for meta-factories that create
+// test factories for passing into MakeAndRegisterTestInfo function.
+template <class ParamType>
+class TestMetaFactoryBase {
+ public:
+ virtual ~TestMetaFactoryBase() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// TestMetaFactory creates test factories for passing into
+// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
+// ownership of test factory pointer, same factory object cannot be passed
+// into that method twice. But ParameterizedTestCaseInfo is going to call
+// it for each Test/Parameter value combination. Thus it needs meta factory
+// creator class.
+template <class TestCase>
+class TestMetaFactory
+ : public TestMetaFactoryBase<typename TestCase::ParamType> {
+ public:
+ typedef typename TestCase::ParamType ParamType;
+
+ TestMetaFactory() {}
+
+ virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
+ return new ParameterizedTestFactory<TestCase>(parameter);
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfoBase is a generic interface
+// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
+// accumulates test information provided by TEST_P macro invocations
+// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
+// and uses that information to register all resulting test instances
+// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
+// a collection of pointers to the ParameterizedTestCaseInfo objects
+// and calls RegisterTests() on each of them when asked.
+class ParameterizedTestCaseInfoBase {
+ public:
+ virtual ~ParameterizedTestCaseInfoBase() {}
+
+ // Base part of test case name for display purposes.
+ virtual const String& GetTestCaseName() const = 0;
+ // Test case id to verify identity.
+ virtual TypeId GetTestCaseTypeId() const = 0;
+ // UnitTest class invokes this method to register tests in this
+ // test case right before running them in RUN_ALL_TESTS macro.
+ // This method should not be called more then once on any single
+ // instance of a ParameterizedTestCaseInfoBase derived class.
+ virtual void RegisterTests() = 0;
+
+ protected:
+ ParameterizedTestCaseInfoBase() {}
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
+};
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
+// macro invocations for a particular test case and generators
+// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
+// test case. It registers tests with all values generated by all
+// generators when asked.
+template <class TestCase>
+class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
+ public:
+ // ParamType and GeneratorCreationFunc are private types but are required
+ // for declarations of public methods AddTestPattern() and
+ // AddTestCaseInstantiation().
+ typedef typename TestCase::ParamType ParamType;
+ // A function that returns an instance of appropriate generator type.
+ typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+
+ explicit ParameterizedTestCaseInfo(const char* name)
+ : test_case_name_(name) {}
+
+ // Test case base name for display purposes.
+ virtual const String& GetTestCaseName() const { return test_case_name_; }
+ // Test case id to verify identity.
+ virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
+ // TEST_P macro uses AddTestPattern() to record information
+ // about a single test in a LocalTestInfo structure.
+ // test_case_name is the base name of the test case (without invocation
+ // prefix). test_base_name is the name of an individual test without
+ // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
+ // test case base name and DoBar is test base name.
+ void AddTestPattern(const char* test_case_name,
+ const char* test_base_name,
+ TestMetaFactoryBase<ParamType>* meta_factory) {
+ tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
+ test_base_name,
+ meta_factory)));
+ }
+ // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
+ // about a generator.
+ int AddTestCaseInstantiation(const char* instantiation_name,
+ GeneratorCreationFunc* func,
+ const char* /* file */,
+ int /* line */) {
+ instantiations_.push_back(::std::make_pair(instantiation_name, func));
+ return 0; // Return value used only to run this method in namespace scope.
+ }
+ // UnitTest class invokes this method to register tests in this test case
+ // test cases right before running tests in RUN_ALL_TESTS macro.
+ // This method should not be called more then once on any single
+ // instance of a ParameterizedTestCaseInfoBase derived class.
+ // UnitTest has a guard to prevent from calling this method more then once.
+ virtual void RegisterTests() {
+ for (typename TestInfoContainer::iterator test_it = tests_.begin();
+ test_it != tests_.end(); ++test_it) {
+ linked_ptr<TestInfo> test_info = *test_it;
+ for (typename InstantiationContainer::iterator gen_it =
+ instantiations_.begin(); gen_it != instantiations_.end();
+ ++gen_it) {
+ const String& instantiation_name = gen_it->first;
+ ParamGenerator<ParamType> generator((*gen_it->second)());
+
+ Message test_case_name_stream;
+ if ( !instantiation_name.empty() )
+ test_case_name_stream << instantiation_name.c_str() << "/";
+ test_case_name_stream << test_info->test_case_base_name.c_str();
+
+ int i = 0;
+ for (typename ParamGenerator<ParamType>::iterator param_it =
+ generator.begin();
+ param_it != generator.end(); ++param_it, ++i) {
+ Message test_name_stream;
+ test_name_stream << test_info->test_base_name.c_str() << "/" << i;
+ ::testing::internal::MakeAndRegisterTestInfo(
+ test_case_name_stream.GetString().c_str(),
+ test_name_stream.GetString().c_str(),
+ "", // test_case_comment
+ "", // comment; TODO(vladl@google.com): provide parameter value
+ // representation.
+ GetTestCaseTypeId(),
+ TestCase::SetUpTestCase,
+ TestCase::TearDownTestCase,
+ test_info->test_meta_factory->CreateTestFactory(*param_it));
+ } // for param_it
+ } // for gen_it
+ } // for test_it
+ } // RegisterTests
+
+ private:
+ // LocalTestInfo structure keeps information about a single test registered
+ // with TEST_P macro.
+ struct TestInfo {
+ TestInfo(const char* a_test_case_base_name,
+ const char* a_test_base_name,
+ TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
+ test_case_base_name(a_test_case_base_name),
+ test_base_name(a_test_base_name),
+ test_meta_factory(a_test_meta_factory) {}
+
+ const String test_case_base_name;
+ const String test_base_name;
+ const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
+ };
+ typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
+ // Keeps pairs of <Instantiation name, Sequence generator creation function>
+ // received from INSTANTIATE_TEST_CASE_P macros.
+ typedef ::std::vector<std::pair<String, GeneratorCreationFunc*> >
+ InstantiationContainer;
+
+ const String test_case_name_;
+ TestInfoContainer tests_;
+ InstantiationContainer instantiations_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
+}; // class ParameterizedTestCaseInfo
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
+// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
+// macros use it to locate their corresponding ParameterizedTestCaseInfo
+// descriptors.
+class ParameterizedTestCaseRegistry {
+ public:
+ ParameterizedTestCaseRegistry() {}
+ ~ParameterizedTestCaseRegistry() {
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ delete *it;
+ }
+ }
+
+ // Looks up or creates and returns a structure containing information about
+ // tests and instantiations of a particular test case.
+ template <class TestCase>
+ ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
+ const char* test_case_name,
+ const char* file,
+ int line) {
+ ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ if ((*it)->GetTestCaseName() == test_case_name) {
+ if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
+ // Complain about incorrect usage of Google Test facilities
+ // and terminate the program since we cannot guaranty correct
+ // test case setup and tear-down in this case.
+ ReportInvalidTestCaseType(test_case_name, file, line);
+ abort();
+ } else {
+ // At this point we are sure that the object we found is of the same
+ // type we are looking for, so we downcast it to that type
+ // without further checks.
+ typed_test_info = CheckedDowncastToActualType<
+ ParameterizedTestCaseInfo<TestCase> >(*it);
+ }
+ break;
+ }
+ }
+ if (typed_test_info == NULL) {
+ typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+ test_case_infos_.push_back(typed_test_info);
+ }
+ return typed_test_info;
+ }
+ void RegisterTests() {
+ for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
+ it != test_case_infos_.end(); ++it) {
+ (*it)->RegisterTests();
+ }
+ }
+
+ private:
+ typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
+
+ TestCaseInfoContainer test_case_infos_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-port.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-port.h
new file mode 100644
index 000000000..fb3b37636
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-port.h
@@ -0,0 +1,1527 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan)
+//
+// Low-level types and utilities for porting Google Test to various
+// platforms. They are subject to change without notice. DO NOT USE
+// THEM IN USER CODE.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
+
+// The user can define the following macros in the build script to
+// control Google Test's behavior. If the user doesn't define a macro
+// in this list, Google Test will define it.
+//
+// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2)
+// is/isn't available.
+// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions
+// are enabled.
+// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define
+// ::string, which is different to std::string).
+// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
+// is/isn't available (some systems define
+// ::wstring, which is different to std::wstring).
+// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h>
+// is/isn't available.
+// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't
+// enabled.
+// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that
+// std::wstring does/doesn't work (Google Test can
+// be used where std::wstring is unavailable).
+// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple
+// is/isn't available.
+// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the
+// compiler supports Microsoft's "Structured
+// Exception Handling".
+// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google
+// Test's own tr1 tuple implementation should be
+// used. Unused when the user sets
+// GTEST_HAS_TR1_TUPLE to 0.
+// GTEST_LINKED_AS_SHARED_LIBRARY
+// - Define to 1 when compiling tests that use
+// Google Test as a shared library (known as
+// DLL on Windows).
+// GTEST_CREATE_SHARED_LIBRARY
+// - Define to 1 when compiling Google Test itself
+// as a shared library.
+
+// This header defines the following utilities:
+//
+// Macros indicating the current platform (defined to 1 if compiled on
+// the given platform; otherwise undefined):
+// GTEST_OS_AIX - IBM AIX
+// GTEST_OS_CYGWIN - Cygwin
+// GTEST_OS_LINUX - Linux
+// GTEST_OS_MAC - Mac OS X
+// GTEST_OS_SOLARIS - Sun Solaris
+// GTEST_OS_SYMBIAN - Symbian
+// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile)
+// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop
+// GTEST_OS_WINDOWS_MINGW - MinGW
+// GTEST_OS_WINDOWS_MOBILE - Windows Mobile
+// GTEST_OS_ZOS - z/OS
+//
+// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
+// most stable support. Since core members of the Google Test project
+// don't have access to other platforms, support for them may be less
+// stable. If you notice any problems on your platform, please notify
+// googletestframework@googlegroups.com (patches for fixing them are
+// even more welcome!).
+//
+// Note that it is possible that none of the GTEST_OS_* macros are defined.
+//
+// Macros indicating available Google Test features (defined to 1 if
+// the corresponding feature is supported; otherwise undefined):
+// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized
+// tests)
+// GTEST_HAS_DEATH_TEST - death tests
+// GTEST_HAS_PARAM_TEST - value-parameterized tests
+// GTEST_HAS_TYPED_TEST - typed tests
+// GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+// GTEST_USES_POSIX_RE - enhanced POSIX regex is used.
+// GTEST_USES_SIMPLE_RE - our own simple regex is used;
+// the above two are mutually exclusive.
+// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
+//
+// Macros for basic C++ coding:
+// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
+// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a
+// variable don't have to be used.
+// GTEST_DISALLOW_ASSIGN_ - disables operator=.
+// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
+// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used.
+//
+// Synchronization:
+// Mutex, MutexLock, ThreadLocal, GetThreadCount()
+// - synchronization primitives.
+// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
+// synchronization primitives have real implementations
+// and Google Test is thread-safe; or 0 otherwise.
+//
+// Template meta programming:
+// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only.
+//
+// Smart pointers:
+// scoped_ptr - as in TR2.
+//
+// Regular expressions:
+// RE - a simple regular expression class using the POSIX
+// Extended Regular Expression syntax. Not available on
+// Windows.
+//
+// Logging:
+// GTEST_LOG_() - logs messages at the specified severity level.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+//
+// Stdout and stderr capturing:
+// CaptureStdout() - starts capturing stdout.
+// GetCapturedStdout() - stops capturing stdout and returns the captured
+// string.
+// CaptureStderr() - starts capturing stderr.
+// GetCapturedStderr() - stops capturing stderr and returns the captured
+// string.
+//
+// Integer types:
+// TypeWithSize - maps an integer to a int type.
+// Int32, UInt32, Int64, UInt64, TimeInMillis
+// - integers of known sizes.
+// BiggestInt - the biggest signed integer type.
+//
+// Command-line utilities:
+// GTEST_FLAG() - references a flag.
+// GTEST_DECLARE_*() - declares a flag.
+// GTEST_DEFINE_*() - defines a flag.
+// GetArgvs() - returns the command line as a vector of strings.
+//
+// Environment variable utilities:
+// GetEnv() - gets the value of an environment variable.
+// BoolFromGTestEnv() - parses a bool environment variable.
+// Int32FromGTestEnv() - parses an Int32 environment variable.
+// StringFromGTestEnv() - parses a string environment variable.
+
+#include <stddef.h> // For ptrdiff_t
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+#include <sys/stat.h>
+#endif // !_WIN32_WCE
+
+#include <wtf/Platform.h>
+#include <wtf/ExportMacros.h>
+#if USE(JSC)
+#include <runtime/JSExportMacros.h>
+#endif
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+
+#include <iostream> // NOLINT
+#include <sstream> // NOLINT
+#include <string> // NOLINT
+
+#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+#define GTEST_FLAG_PREFIX_ "gtest_"
+#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+#define GTEST_NAME_ "Google Test"
+#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+#define GTEST_GCC_VER_ \
+ (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif // __GNUC__
+
+// Determines the platform on which Google Test is compiled.
+#ifdef __CYGWIN__
+#define GTEST_OS_CYGWIN 1
+#elif defined __SYMBIAN32__
+#define GTEST_OS_SYMBIAN 1
+#elif defined _WIN32
+#define GTEST_OS_WINDOWS 1
+#ifdef _WIN32_WCE
+#define GTEST_OS_WINDOWS_MOBILE 1
+#elif defined(__MINGW__) || defined(__MINGW32__)
+#define GTEST_OS_WINDOWS_MINGW 1
+#else
+#define GTEST_OS_WINDOWS_DESKTOP 1
+#endif // _WIN32_WCE
+#elif defined __APPLE__
+#define GTEST_OS_MAC 1
+#elif defined __linux__
+#define GTEST_OS_LINUX 1
+#elif defined __MVS__
+#define GTEST_OS_ZOS 1
+#elif defined(__sun) && defined(__SVR4)
+#define GTEST_OS_SOLARIS 1
+#elif defined(_AIX)
+#define GTEST_OS_AIX 1
+#endif // __CYGWIN__
+
+#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SYMBIAN || \
+ GTEST_OS_SOLARIS || GTEST_OS_AIX
+
+// On some platforms, <regex.h> needs someone to define size_t, and
+// won't compile otherwise. We can #include it here as we already
+// included <stdlib.h>, which is guaranteed to define size_t through
+// <stddef.h>.
+#include <regex.h> // NOLINT
+#include <strings.h> // NOLINT
+#include <sys/types.h> // NOLINT
+#include <time.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+#define GTEST_USES_POSIX_RE 1
+
+#elif GTEST_OS_WINDOWS
+
+#if !GTEST_OS_WINDOWS_MOBILE
+#include <direct.h> // NOLINT
+#include <io.h> // NOLINT
+#endif
+
+// <regex.h> is not available on Windows. Use our own simple regex
+// implementation instead.
+#define GTEST_USES_SIMPLE_RE 1
+
+#else
+
+// <regex.h> may not be available on this platform. Use our own
+// simple regex implementation instead.
+#define GTEST_USES_SIMPLE_RE 1
+
+#endif // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC ||
+ // GTEST_OS_SYMBIAN || GTEST_OS_SOLARIS || GTEST_OS_AIX
+
+#ifndef GTEST_HAS_EXCEPTIONS
+// The user didn't tell us whether exceptions are enabled, so we need
+// to figure it out.
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
+// macro to enable exceptions, so we'll do the same.
+// Assumes that exceptions are enabled by default.
+#ifndef _HAS_EXCEPTIONS
+#define _HAS_EXCEPTIONS 1
+#endif // _HAS_EXCEPTIONS
+#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+#elif defined(__GNUC__) && __EXCEPTIONS
+// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
+#define GTEST_HAS_EXCEPTIONS 1
+#elif defined(__SUNPRO_CC)
+// Sun Pro CC supports exceptions. However, there is no compile-time way of
+// detecting whether they are enabled or not. Therefore, we assume that
+// they are enabled unless the user tells us otherwise.
+#define GTEST_HAS_EXCEPTIONS 1
+#elif defined(__IBMCPP__) && __EXCEPTIONS
+// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
+#define GTEST_HAS_EXCEPTIONS 1
+#else
+// For other compilers, we assume exceptions are disabled to be
+// conservative.
+#define GTEST_HAS_EXCEPTIONS 0
+#endif // defined(_MSC_VER) || defined(__BORLANDC__)
+#endif // GTEST_HAS_EXCEPTIONS
+
+#if !defined(GTEST_HAS_STD_STRING)
+// Even though we don't use this macro any longer, we keep it in case
+// some clients still depend on it.
+#define GTEST_HAS_STD_STRING 1
+#elif !GTEST_HAS_STD_STRING
+// The user told us that ::std::string isn't available.
+#error "Google Test cannot be used where ::std::string isn't available."
+#endif // !defined(GTEST_HAS_STD_STRING)
+
+#ifndef GTEST_HAS_GLOBAL_STRING
+// The user didn't tell us whether ::string is available, so we need
+// to figure it out.
+
+#define GTEST_HAS_GLOBAL_STRING 0
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#ifndef GTEST_HAS_STD_WSTRING
+// The user didn't tell us whether ::std::wstring is available, so we need
+// to figure it out.
+// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
+// is available.
+
+// Cygwin 1.5 and below doesn't support ::std::wstring.
+// Cygwin 1.7 might add wstring support; this should be updated when clear.
+// Solaris' libc++ doesn't support it either.
+#define GTEST_HAS_STD_WSTRING (!(GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))
+
+#endif // GTEST_HAS_STD_WSTRING
+
+#ifndef GTEST_HAS_GLOBAL_WSTRING
+// The user didn't tell us whether ::wstring is available, so we need
+// to figure it out.
+#define GTEST_HAS_GLOBAL_WSTRING \
+ (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Determines whether RTTI is available.
+#ifndef GTEST_HAS_RTTI
+// The user didn't tell us whether RTTI is enabled, so we need to
+// figure it out.
+
+#ifdef _MSC_VER
+
+#ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled.
+#define GTEST_HAS_RTTI 1
+#else
+#define GTEST_HAS_RTTI 0
+#endif
+
+// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
+#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
+
+#ifdef __GXX_RTTI
+#define GTEST_HAS_RTTI 1
+#else
+#define GTEST_HAS_RTTI 0
+#endif // __GXX_RTTI
+
+// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
+// both the typeid and dynamic_cast features are present.
+#elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
+
+#ifdef __RTTI_ALL__
+#define GTEST_HAS_RTTI 1
+#else
+#define GTEST_HAS_RTTI 0
+#endif
+
+#else
+
+// For all other compilers, we assume RTTI is enabled.
+#define GTEST_HAS_RTTI 1
+
+#endif // _MSC_VER
+
+#endif // GTEST_HAS_RTTI
+
+// It's this header's responsibility to #include <typeinfo> when RTTI
+// is enabled.
+#if GTEST_HAS_RTTI
+#include <typeinfo>
+#endif
+
+// Determines whether Google Test can use the pthreads library.
+#ifndef GTEST_HAS_PTHREAD
+// The user didn't tell us explicitly, so we assume pthreads support is
+// available on Linux and Mac.
+//
+// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
+// to your compiler flags.
+#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC)
+#endif // GTEST_HAS_PTHREAD
+
+// Determines whether Google Test can use tr1/tuple. You can define
+// this macro to 0 to prevent Google Test from using tuple (any
+// feature depending on tuple with be disabled in this mode).
+#ifndef GTEST_HAS_TR1_TUPLE
+// The user didn't tell us not to do it, so we assume it's OK.
+#define GTEST_HAS_TR1_TUPLE 1
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Determines whether Google Test's own tr1 tuple implementation
+// should be used.
+#ifndef GTEST_USE_OWN_TR1_TUPLE
+// The user didn't tell us, so we need to figure it out.
+
+// We use our own TR1 tuple if we aren't sure the user has an
+// implementation of it already. At this time, GCC 4.0.0+ and MSVC
+// 2010 are the only mainstream compilers that come with a TR1 tuple
+// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by
+// defining __GNUC__ and friends, but cannot compile GCC's tuple
+// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB
+// Feature Pack download, which we cannot assume the user has.
+#if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \
+ || _MSC_VER >= 1600
+#define GTEST_USE_OWN_TR1_TUPLE 0
+#else
+#define GTEST_USE_OWN_TR1_TUPLE 1
+#endif
+
+#endif // GTEST_USE_OWN_TR1_TUPLE
+
+// To avoid conditional compilation everywhere, we make it
+// gtest-port.h's responsibility to #include the header implementing
+// tr1/tuple.
+#if GTEST_HAS_TR1_TUPLE
+
+#if GTEST_USE_OWN_TR1_TUPLE
+#include <gtest/internal/gtest-tuple.h>
+#elif GTEST_OS_SYMBIAN
+
+// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
+// use STLport's tuple implementation, which unfortunately doesn't
+// work as the copy of STLport distributed with Symbian is incomplete.
+// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
+// use its own tuple implementation.
+#ifdef BOOST_HAS_TR1_TUPLE
+#undef BOOST_HAS_TR1_TUPLE
+#endif // BOOST_HAS_TR1_TUPLE
+
+// This prevents <boost/tr1/detail/config.hpp>, which defines
+// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
+#define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
+#include <tuple>
+
+#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
+// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header. This does
+// not conform to the TR1 spec, which requires the header to be <tuple>.
+
+#if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
+// which is #included by <tr1/tuple>, to not compile when RTTI is
+// disabled. _TR1_FUNCTIONAL is the header guard for
+// <tr1/functional>. Hence the following #define is a hack to prevent
+// <tr1/functional> from being included.
+#define _TR1_FUNCTIONAL 1
+#include <tr1/tuple>
+#undef _TR1_FUNCTIONAL // Allows the user to #include
+ // <tr1/functional> if he chooses to.
+#else
+#include <tr1/tuple> // NOLINT
+#endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
+
+#else
+// If the compiler is not GCC 4.0+, we assume the user is using a
+// spec-conforming TR1 implementation.
+#include <tuple> // NOLINT
+#endif // GTEST_USE_OWN_TR1_TUPLE
+
+#endif // GTEST_HAS_TR1_TUPLE
+
+// Determines whether clone(2) is supported.
+// Usually it will only be available on Linux, excluding
+// Linux on the Itanium architecture.
+// Also see http://linux.die.net/man/2/clone.
+#ifndef GTEST_HAS_CLONE
+// The user didn't tell us, so we need to figure it out.
+
+#if GTEST_OS_LINUX && !defined(__ia64__)
+#define GTEST_HAS_CLONE 1
+#else
+#define GTEST_HAS_CLONE 0
+#endif // GTEST_OS_LINUX && !defined(__ia64__)
+
+#endif // GTEST_HAS_CLONE
+
+// Determines whether to support stream redirection. This is used to test
+// output correctness and to implement death tests.
+#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
+#define GTEST_HAS_STREAM_REDIRECTION_ 1
+#endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
+
+// Determines whether to support death tests.
+// Google Test does not support death tests for VC 7.1 and earlier as
+// abort() in a VC 7.1 application compiled as GUI in debug config
+// pops up a dialog window that cannot be suppressed programmatically.
+#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
+ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
+ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX)
+#define GTEST_HAS_DEATH_TEST 1
+#include <vector> // NOLINT
+#endif
+
+// We don't support MSVC 7.1 with exceptions disabled now. Therefore
+// all the compilers we care about are adequate for supporting
+// value-parameterized tests.
+#define GTEST_HAS_PARAM_TEST 1
+
+// Determines whether to support type-driven tests.
+
+// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
+// Sun Pro CC, and IBM Visual Age support.
+#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \
+ defined(__IBMCPP__)
+#define GTEST_HAS_TYPED_TEST 1
+#define GTEST_HAS_TYPED_TEST_P 1
+#endif
+
+// Determines whether to support Combine(). This only makes sense when
+// value-parameterized tests are enabled. The implementation doesn't
+// work on Sun Studio since it doesn't understand templated conversion
+// operators.
+#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC)
+#define GTEST_HAS_COMBINE 1
+#endif
+
+// Determines whether the system compiler uses UTF-16 for encoding wide strings.
+#define GTEST_WIDE_STRING_USES_UTF16_ \
+ (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX)
+
+// Defines some utility macros.
+
+// The GNU compiler emits a warning if nested "if" statements are followed by
+// an "else" statement and braces are not used to explicitly disambiguate the
+// "else" binding. This leads to problems with code like:
+//
+// if (gate)
+// ASSERT_*(condition) << "Some message";
+//
+// The "switch (0) case 0:" idiom is used to suppress this.
+#ifdef __INTEL_COMPILER
+#define GTEST_AMBIGUOUS_ELSE_BLOCKER_
+#else
+#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: // NOLINT
+#endif
+
+// Use this annotation at the end of a struct/class definition to
+// prevent the compiler from optimizing away instances that are never
+// used. This is useful when all interesting logic happens inside the
+// c'tor and / or d'tor. Example:
+//
+// struct Foo {
+// Foo() { ... }
+// } GTEST_ATTRIBUTE_UNUSED_;
+//
+// Also use it after a variable or parameter declaration to tell the
+// compiler the variable/parameter does not have to be used.
+#if defined(__GNUC__) && !defined(COMPILER_ICC)
+#define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+#else
+#define GTEST_ATTRIBUTE_UNUSED_
+#endif
+
+// A macro to disallow operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_ASSIGN_(type)\
+ void operator=(type const &)
+
+// A macro to disallow copy constructor and operator=
+// This should be used in the private: declarations for a class.
+#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
+ type(type const &);\
+ GTEST_DISALLOW_ASSIGN_(type)
+
+// Tell the compiler to warn about unused return values for functions declared
+// with this macro. The macro should be used on function declarations
+// following the argument list:
+//
+// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
+#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
+#define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
+#else
+#define GTEST_MUST_USE_RESULT_
+#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
+
+// Determine whether the compiler supports Microsoft's Structured Exception
+// Handling. This is supported by several Windows compilers but generally
+// does not exist on any other system.
+#ifndef GTEST_HAS_SEH
+// The user didn't tell us, so we need to figure it out.
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// These two compilers are known to support SEH.
+#define GTEST_HAS_SEH 1
+#else
+// Assume no SEH.
+#define GTEST_HAS_SEH 0
+#endif
+
+#endif // GTEST_HAS_SEH
+
+#ifdef _MSC_VER
+
+#if GTEST_LINKED_AS_SHARED_LIBRARY
+#define GTEST_API_ __declspec(dllimport)
+#elif GTEST_CREATE_SHARED_LIBRARY
+#define GTEST_API_ __declspec(dllexport)
+#endif
+
+#endif // _MSC_VER
+
+#ifndef GTEST_API_
+#define GTEST_API_
+#endif
+
+namespace testing {
+
+class Message;
+
+namespace internal {
+
+class String;
+
+class StrStream : public ::std::stringstream {
+ public:
+ void* operator new(size_t, void* p) { return p; }
+ void* operator new[](size_t, void* p) { return p; }
+
+ void* operator new(size_t size) {
+ return malloc(size);
+ }
+
+ void operator delete(void* p) {
+ free(p);
+ }
+
+ void* operator new[](size_t size) {
+ return malloc(size);
+ }
+
+ void operator delete[](void* p) {
+ free(p);
+ }
+};
+
+
+
+// A helper for suppressing warnings on constant condition. It just
+// returns 'condition'.
+GTEST_API_ bool IsTrue(bool condition);
+
+// Defines scoped_ptr.
+
+// This implementation of scoped_ptr is PARTIAL - it only contains
+// enough stuff to satisfy Google Test's need.
+template <typename T>
+class scoped_ptr {
+ public:
+ typedef T element_type;
+
+ explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
+ ~scoped_ptr() { reset(); }
+
+ T& operator*() const { return *ptr_; }
+ T* operator->() const { return ptr_; }
+ T* get() const { return ptr_; }
+
+ T* release() {
+ T* const ptr = ptr_;
+ ptr_ = NULL;
+ return ptr;
+ }
+
+ void reset(T* p = NULL) {
+ if (p != ptr_) {
+ if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type.
+ delete ptr_;
+ }
+ ptr_ = p;
+ }
+ }
+ private:
+ T* ptr_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
+};
+
+// Defines RE.
+
+// A simple C++ wrapper for <regex.h>. It uses the POSIX Extended
+// Regular Expression syntax.
+class GTEST_API_ RE {
+ public:
+ // A copy constructor is required by the Standard to initialize object
+ // references from r-values.
+ RE(const RE& other) { Init(other.pattern()); }
+
+ // Constructs an RE from a string.
+ RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT
+
+#if GTEST_HAS_GLOBAL_STRING
+ RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ RE(const char* regex) { Init(regex); } // NOLINT
+ ~RE();
+
+ // Returns the string representation of the regex.
+ const char* pattern() const { return pattern_; }
+
+ // FullMatch(str, re) returns true iff regular expression re matches
+ // the entire str.
+ // PartialMatch(str, re) returns true iff regular expression re
+ // matches a substring of str (including str itself).
+ //
+ // TODO(wan@google.com): make FullMatch() and PartialMatch() work
+ // when str contains NUL characters.
+ static bool FullMatch(const ::std::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::std::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+
+#if GTEST_HAS_GLOBAL_STRING
+ static bool FullMatch(const ::string& str, const RE& re) {
+ return FullMatch(str.c_str(), re);
+ }
+ static bool PartialMatch(const ::string& str, const RE& re) {
+ return PartialMatch(str.c_str(), re);
+ }
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ static bool FullMatch(const char* str, const RE& re);
+ static bool PartialMatch(const char* str, const RE& re);
+
+ private:
+ void Init(const char* regex);
+
+ // We use a const char* instead of a string, as Google Test may be used
+ // where string is not available. We also do not use Google Test's own
+ // String type here, in order to simplify dependencies between the
+ // files.
+ const char* pattern_;
+ bool is_valid_;
+#if GTEST_USES_POSIX_RE
+ regex_t full_regex_; // For FullMatch().
+ regex_t partial_regex_; // For PartialMatch().
+#else // GTEST_USES_SIMPLE_RE
+ const char* full_pattern_; // For FullMatch();
+#endif
+
+ GTEST_DISALLOW_ASSIGN_(RE);
+};
+
+// Defines logging utilities:
+// GTEST_LOG_(severity) - logs messages at the specified severity level. The
+// message itself is streamed into the macro.
+// LogToStderr() - directs all log messages to stderr.
+// FlushInfoLog() - flushes informational log messages.
+
+enum GTestLogSeverity {
+ GTEST_INFO,
+ GTEST_WARNING,
+ GTEST_ERROR,
+ GTEST_FATAL
+};
+
+// Formats log entry severity, provides a stream object for streaming the
+// log message, and terminates the message with a newline when going out of
+// scope.
+class GTEST_API_ GTestLog {
+ public:
+ GTestLog(GTestLogSeverity severity, const char* file, int line);
+
+ // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+ ~GTestLog();
+
+ ::std::ostream& GetStream() { return ::std::cerr; }
+
+ private:
+ const GTestLogSeverity severity_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
+};
+
+#define GTEST_LOG_(severity) \
+ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
+ __FILE__, __LINE__).GetStream()
+
+inline void LogToStderr() {}
+inline void FlushInfoLog() { fflush(NULL); }
+
+// INTERNAL IMPLEMENTATION - DO NOT USE.
+//
+// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
+// is not satisfied.
+// Synopsys:
+// GTEST_CHECK_(boolean_condition);
+// or
+// GTEST_CHECK_(boolean_condition) << "Additional message";
+//
+// This checks the condition and if the condition is not satisfied
+// it prints message about the condition violation, including the
+// condition itself, plus additional message streamed into it, if any,
+// and then it aborts the program. It aborts the program irrespective of
+// whether it is built in the debug mode or not.
+#define GTEST_CHECK_(condition) \
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
+ if (::testing::internal::IsTrue(condition)) \
+ ; \
+ else \
+ GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
+
+// An all-mode assert to verify that the given POSIX-style function
+// call returns 0 (indicating success). Known limitation: this
+// doesn't expand to a balanced 'if' statement, so enclose the macro
+// in {} if you need to use it as the only statement in an 'if'
+// branch.
+#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \
+ if (const int gtest_error = (posix_call)) \
+ GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
+ << gtest_error
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Downcasts the pointer of type Base to Derived.
+// Derived must be a subclass of Base. The parameter MUST
+// point to a class of type Derived, not any subclass of it.
+// When RTTI is available, the function performs a runtime
+// check to enforce this.
+template <class Derived, class Base>
+Derived* CheckedDowncastToActualType(Base* base) {
+#if GTEST_HAS_RTTI
+ GTEST_CHECK_(typeid(*base) == typeid(Derived));
+ return dynamic_cast<Derived*>(base); // NOLINT
+#else
+ return static_cast<Derived*>(base); // Poor man's downcast.
+#endif
+}
+
+#if GTEST_HAS_STREAM_REDIRECTION_
+
+// Defines the stderr capturer:
+// CaptureStdout - starts capturing stdout.
+// GetCapturedStdout - stops capturing stdout and returns the captured string.
+// CaptureStderr - starts capturing stderr.
+// GetCapturedStderr - stops capturing stderr and returns the captured string.
+//
+GTEST_API_ void CaptureStdout();
+GTEST_API_ String GetCapturedStdout();
+GTEST_API_ void CaptureStderr();
+GTEST_API_ String GetCapturedStderr();
+
+#endif // GTEST_HAS_STREAM_REDIRECTION_
+
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+extern ::std::vector<String> g_argvs;
+
+// GTEST_HAS_DEATH_TEST implies we have ::std::string.
+const ::std::vector<String>& GetArgvs();
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Defines synchronization primitives.
+
+#if GTEST_HAS_PTHREAD
+
+// Sleeps for (roughly) n milli-seconds. This function is only for
+// testing Google Test's own constructs. Don't use it in user tests,
+// either directly or indirectly.
+inline void SleepMilliseconds(int n) {
+ const timespec time = {
+ 0, // 0 seconds.
+ n * 1000L * 1000L, // And n ms.
+ };
+ nanosleep(&time, NULL);
+}
+
+// Allows a controller thread to pause execution of newly created
+// threads until notified. Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class Notification {
+ public:
+ Notification() : notified_(false) {}
+
+ // Notifies all threads created with this notification to start. Must
+ // be called from the controller thread.
+ void Notify() { notified_ = true; }
+
+ // Blocks until the controller thread notifies. Must be called from a test
+ // thread.
+ void WaitForNotification() {
+ while(!notified_) {
+ SleepMilliseconds(10);
+ }
+ }
+
+ private:
+ volatile bool notified_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+
+// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
+// Consequently, it cannot select a correct instantiation of ThreadWithParam
+// in order to call its Run(). Introducing ThreadWithParamBase as a
+// non-templated base class for ThreadWithParam allows us to bypass this
+// problem.
+class ThreadWithParamBase {
+ public:
+ virtual ~ThreadWithParamBase() {}
+ virtual void Run() = 0;
+};
+
+// pthread_create() accepts a pointer to a function type with the C linkage.
+// According to the Standard (7.5/1), function types with different linkages
+// are different even if they are otherwise identical. Some compilers (for
+// example, SunStudio) treat them as different types. Since class methods
+// cannot be defined with C-linkage we need to define a free C-function to
+// pass into pthread_create().
+extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
+ static_cast<ThreadWithParamBase*>(thread)->Run();
+ return NULL;
+}
+
+// Helper class for testing Google Test's multi-threading constructs.
+// To use it, write:
+//
+// void ThreadFunc(int param) { /* Do things with param */ }
+// Notification thread_can_start;
+// ...
+// // The thread_can_start parameter is optional; you can supply NULL.
+// ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
+// thread_can_start.Notify();
+//
+// These classes are only for testing Google Test's own constructs. Do
+// not use them in user tests, either directly or indirectly.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+ typedef void (*UserThreadFunc)(T);
+
+ ThreadWithParam(
+ UserThreadFunc func, T param, Notification* thread_can_start)
+ : func_(func),
+ param_(param),
+ thread_can_start_(thread_can_start),
+ finished_(false) {
+ ThreadWithParamBase* const base = this;
+ // The thread can be created only after all fields except thread_
+ // have been initialized.
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
+ }
+ ~ThreadWithParam() { Join(); }
+
+ void Join() {
+ if (!finished_) {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
+ finished_ = true;
+ }
+ }
+
+ virtual void Run() {
+ if (thread_can_start_ != NULL)
+ thread_can_start_->WaitForNotification();
+ func_(param_);
+ }
+
+ private:
+ const UserThreadFunc func_; // User-supplied thread function.
+ const T param_; // User-supplied parameter to the thread function.
+ // When non-NULL, used to block execution until the controller thread
+ // notifies.
+ Notification* const thread_can_start_;
+ bool finished_; // true iff we know that the thread function has finished.
+ pthread_t thread_; // The native thread object.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+
+// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
+// true.
+#include <pthread.h>
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms. They
+// are used in conjunction with class MutexLock:
+//
+// Mutex mutex;
+// ...
+// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end
+// // of the current scope.
+//
+// MutexBase implements behavior for both statically and dynamically
+// allocated mutexes. Do not use MutexBase directly. Instead, write
+// the following to define a static mutex:
+//
+// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+//
+// You can forward declare a static mutex like this:
+//
+// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+//
+// To create a dynamic mutex, just define an object of type Mutex.
+class MutexBase {
+ public:
+ // Acquires this mutex.
+ void Lock() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
+ owner_ = pthread_self();
+ }
+
+ // Releases this mutex.
+ void Unlock() {
+ // We don't protect writing to owner_ here, as it's the caller's
+ // responsibility to ensure that the current thread holds the
+ // mutex when this is called.
+ owner_ = 0;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
+ }
+
+ // Does nothing if the current thread holds the mutex. Otherwise, crashes
+ // with high probability.
+ void AssertHeld() const {
+ GTEST_CHECK_(owner_ == pthread_self())
+ << "The current thread is not holding the mutex @" << this;
+ }
+
+ // A static mutex may be used before main() is entered. It may even
+ // be used before the dynamic initialization stage. Therefore we
+ // must be able to initialize a static mutex object at link time.
+ // This means MutexBase has to be a POD and its member variables
+ // have to be public.
+ public:
+ pthread_mutex_t mutex_; // The underlying pthread mutex.
+ pthread_t owner_; // The thread holding the mutex; 0 means no one holds it.
+};
+
+// Forward-declares a static mutex.
+#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::MutexBase mutex
+
+// Defines and statically (i.e. at link time) initializes a static mutex.
+#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+ ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 }
+
+// The Mutex class can only be used for mutexes created at runtime. It
+// shares its API with MutexBase otherwise.
+class Mutex : public MutexBase {
+ public:
+ Mutex() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
+ owner_ = 0;
+ }
+ ~Mutex() {
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
+ }
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+// We cannot name this class MutexLock as the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(MutexBase* mutex)
+ : mutex_(mutex) { mutex_->Lock(); }
+
+ ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+ MutexBase* const mutex_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Helpers for ThreadLocal.
+
+// pthread_key_create() requires DeleteThreadLocalValue() to have
+// C-linkage. Therefore it cannot be templatized to access
+// ThreadLocal<T>. Hence the need for class
+// ThreadLocalValueHolderBase.
+class ThreadLocalValueHolderBase {
+ public:
+ virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Called by pthread to delete thread-local data stored by
+// pthread_setspecific().
+extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
+ delete static_cast<ThreadLocalValueHolderBase*>(value_holder);
+}
+
+// Implements thread-local storage on pthreads-based systems.
+//
+// // Thread 1
+// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
+//
+// // Thread 2
+// tl.set(150); // Changes the value for thread 2 only.
+// EXPECT_EQ(150, tl.get());
+//
+// // Thread 1
+// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
+// tl.set(200);
+// EXPECT_EQ(200, tl.get());
+//
+// The template type argument T must have a public copy constructor.
+// In addition, the default ThreadLocal constructor requires T to have
+// a public default constructor.
+//
+// An object managed for a thread by a ThreadLocal instance is deleted
+// when the thread exits. Or, if the ThreadLocal instance dies in
+// that thread, when the ThreadLocal dies. It's the user's
+// responsibility to ensure that all other threads using a ThreadLocal
+// have exited when it dies, or the per-thread objects for those
+// threads will not be deleted.
+//
+// Google Test only uses global ThreadLocal objects. That means they
+// will die after main() has returned. Therefore, no per-thread
+// object managed by Google Test will be leaked as long as all threads
+// using Google Test have exited when main() returns.
+template <typename T>
+class ThreadLocal {
+ public:
+ ThreadLocal() : key_(CreateKey()),
+ default_() {}
+ explicit ThreadLocal(const T& value) : key_(CreateKey()),
+ default_(value) {}
+
+ ~ThreadLocal() {
+ // Destroys the managed object for the current thread, if any.
+ DeleteThreadLocalValue(pthread_getspecific(key_));
+
+ // Releases resources associated with the key. This will *not*
+ // delete managed objects for other threads.
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_));
+ }
+
+ T* pointer() { return GetOrCreateValue(); }
+ const T* pointer() const { return GetOrCreateValue(); }
+ const T& get() const { return *pointer(); }
+ void set(const T& value) { *pointer() = value; }
+
+ private:
+ // Holds a value of type T.
+ class ValueHolder : public ThreadLocalValueHolderBase {
+ public:
+ explicit ValueHolder(const T& value) : value_(value) {}
+
+ T* pointer() { return &value_; }
+
+ private:
+ T value_;
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+ };
+
+ static pthread_key_t CreateKey() {
+ pthread_key_t key;
+ // When a thread exits, DeleteThreadLocalValue() will be called on
+ // the object managed for that thread.
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_key_create(&key, &DeleteThreadLocalValue));
+ return key;
+ }
+
+ T* GetOrCreateValue() const {
+ ThreadLocalValueHolderBase* const holder =
+ static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
+ if (holder != NULL) {
+ return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
+ }
+
+ ValueHolder* const new_holder = new ValueHolder(default_);
+ ThreadLocalValueHolderBase* const holder_base = new_holder;
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
+ return new_holder->pointer();
+ }
+
+ // A key pthreads uses for looking up per-thread values.
+ const pthread_key_t key_;
+ const T default_; // The default value for each thread.
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
+};
+
+#define GTEST_IS_THREADSAFE 1
+
+#else // GTEST_HAS_PTHREAD
+
+// A dummy implementation of synchronization primitives (mutex, lock,
+// and thread-local variable). Necessary for compiling Google Test where
+// mutex is not supported - using Google Test in multiple threads is not
+// supported on such platforms.
+
+class Mutex {
+ public:
+ Mutex() {}
+ void AssertHeld() const {}
+};
+
+#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+ extern ::testing::internal::Mutex mutex
+
+#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
+
+class GTestMutexLock {
+ public:
+ explicit GTestMutexLock(Mutex*) {} // NOLINT
+};
+
+typedef GTestMutexLock MutexLock;
+
+template <typename T>
+class ThreadLocal {
+ public:
+ ThreadLocal() : value_() {}
+ explicit ThreadLocal(const T& value) : value_(value) {}
+ T* pointer() { return &value_; }
+ const T* pointer() const { return &value_; }
+ const T& get() const { return value_; }
+ void set(const T& value) { value_ = value; }
+ private:
+ T value_;
+};
+
+// The above synchronization primitives have dummy implementations.
+// Therefore Google Test is not thread-safe.
+#define GTEST_IS_THREADSAFE 0
+
+#endif // GTEST_HAS_PTHREAD
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+GTEST_API_ size_t GetThreadCount();
+
+// Passing non-POD classes through ellipsis (...) crashes the ARM
+// compiler and generates a warning in Sun Studio. The Nokia Symbian
+// and the IBM XL C/C++ compiler try to instantiate a copy constructor
+// for objects passed through ellipsis (...), failing for uncopyable
+// objects. We define this to ensure that only POD is passed through
+// ellipsis on these systems.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC)
+// We lose support for NULL detection where the compiler doesn't like
+// passing non-POD classes through ellipsis (...).
+#define GTEST_ELLIPSIS_NEEDS_POD_ 1
+#else
+#define GTEST_CAN_COMPARE_NULL 1
+#endif
+
+// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
+// const T& and const T* in a function template. These compilers
+// _can_ decide between class template specializations for T and T*,
+// so a tr1::type_traits-like is_pointer works.
+#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
+#define GTEST_NEEDS_IS_POINTER_ 1
+#endif
+
+template <bool bool_value>
+struct bool_constant {
+ typedef bool_constant<bool_value> type;
+ static const bool value = bool_value;
+};
+template <bool bool_value> const bool bool_constant<bool_value>::value;
+
+typedef bool_constant<false> false_type;
+typedef bool_constant<true> true_type;
+
+template <typename T>
+struct is_pointer : public false_type {};
+
+template <typename T>
+struct is_pointer<T*> : public true_type {};
+
+#if GTEST_OS_WINDOWS
+#define GTEST_PATH_SEP_ "\\"
+#define GTEST_HAS_ALT_PATH_SEP_ 1
+// The biggest signed integer type the compiler supports.
+typedef __int64 BiggestInt;
+#else
+#define GTEST_PATH_SEP_ "/"
+#define GTEST_HAS_ALT_PATH_SEP_ 0
+typedef long long BiggestInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+
+// The testing::internal::posix namespace holds wrappers for common
+// POSIX functions. These wrappers hide the differences between
+// Windows/MSVC and POSIX systems. Since some compilers define these
+// standard functions as macros, the wrapper cannot have the same name
+// as the wrapped function.
+
+namespace posix {
+
+// Functions with a different name on Windows.
+
+#if GTEST_OS_WINDOWS
+
+typedef struct _stat StatStruct;
+
+#ifdef __BORLANDC__
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+#else // !__BORLANDC__
+#if GTEST_OS_WINDOWS_MOBILE
+inline int IsATTY(int /* fd */) { return 0; }
+#else
+inline int IsATTY(int fd) { return _isatty(fd); }
+#endif // GTEST_OS_WINDOWS_MOBILE
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return _stricmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return _strdup(src); }
+#endif // __BORLANDC__
+
+#if GTEST_OS_WINDOWS_MOBILE
+inline int FileNo(FILE* file) { return reinterpret_cast<int>(_fileno(file)); }
+// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this
+// time and thus not defined there.
+#else
+inline int FileNo(FILE* file) { return _fileno(file); }
+inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
+inline int RmDir(const char* dir) { return _rmdir(dir); }
+inline bool IsDir(const StatStruct& st) {
+ return (_S_IFDIR & st.st_mode) != 0;
+}
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#else
+
+typedef struct stat StatStruct;
+
+inline int FileNo(FILE* file) { return fileno(file); }
+inline int IsATTY(int fd) { return isatty(fd); }
+inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
+inline int StrCaseCmp(const char* s1, const char* s2) {
+ return strcasecmp(s1, s2);
+}
+inline char* StrDup(const char* src) { return strdup(src); }
+inline int RmDir(const char* dir) { return rmdir(dir); }
+inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
+
+#endif // GTEST_OS_WINDOWS
+
+// Functions deprecated by MSVC 8.0.
+
+#ifdef _MSC_VER
+// Temporarily disable warning 4996 (deprecated function).
+#pragma warning(push)
+#pragma warning(disable:4996)
+#endif
+
+inline const char* StrNCpy(char* dest, const char* src, size_t n) {
+ return strncpy(dest, src, n);
+}
+
+// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
+// StrError() aren't needed on Windows CE at this time and thus not
+// defined there.
+
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int ChDir(const char* dir) { return chdir(dir); }
+#endif
+inline FILE* FOpen(const char* path, const char* mode) {
+ return fopen(path, mode);
+}
+#if !GTEST_OS_WINDOWS_MOBILE
+inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
+ return freopen(path, mode, stream);
+}
+inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
+#endif
+inline int FClose(FILE* fp) { return fclose(fp); }
+#if !GTEST_OS_WINDOWS_MOBILE
+inline int Read(int fd, void* buf, unsigned int count) {
+ return static_cast<int>(read(fd, buf, count));
+}
+inline int Write(int fd, const void* buf, unsigned int count) {
+ return static_cast<int>(write(fd, buf, count));
+}
+inline int Close(int fd) { return close(fd); }
+inline const char* StrError(int errnum) { return strerror(errnum); }
+#endif
+inline const char* GetEnv(const char* name) {
+#if GTEST_OS_WINDOWS_MOBILE
+ // We are on Windows CE, which has no environment variables.
+ return NULL;
+#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
+ // Environment variables which we programmatically clear will be set to the
+ // empty string rather than unset (NULL). Handle that case.
+ const char* const env = getenv(name);
+ return (env != NULL && env[0] != '\0') ? env : NULL;
+#else
+ return getenv(name);
+#endif
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop) // Restores the warning state.
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Windows CE has no C library. The abort() function is used in
+// several places in Google Test. This implementation provides a reasonable
+// imitation of standard behaviour.
+void Abort();
+#else
+inline void Abort() { abort(); }
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+} // namespace posix
+
+// The maximum number a BiggestInt can represent. This definition
+// works no matter BiggestInt is represented in one's complement or
+// two's complement.
+//
+// We cannot rely on numeric_limits in STL, as __int64 and long long
+// are not part of standard C++ and numeric_limits doesn't need to be
+// defined for them.
+const BiggestInt kMaxBiggestInt =
+ ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
+
+// This template class serves as a compile-time function from size to
+// type. It maps a size in bytes to a primitive type with that
+// size. e.g.
+//
+// TypeWithSize<4>::UInt
+//
+// is typedef-ed to be unsigned int (unsigned integer made up of 4
+// bytes).
+//
+// Such functionality should belong to STL, but I cannot find it
+// there.
+//
+// Google Test uses this class in the implementation of floating-point
+// comparison.
+//
+// For now it only handles UInt (unsigned int) as that's all Google Test
+// needs. Other types can be easily added in the future if need
+// arises.
+template <size_t size>
+class TypeWithSize {
+ public:
+ // This prevents the user from using TypeWithSize<N> with incorrect
+ // values of N.
+ typedef void UInt;
+};
+
+// The specialization for size 4.
+template <>
+class TypeWithSize<4> {
+ public:
+ // unsigned int has size 4 in both gcc and MSVC.
+ //
+ // As base/basictypes.h doesn't compile on Windows, we cannot use
+ // uint32, uint64, and etc here.
+ typedef int Int;
+ typedef unsigned int UInt;
+};
+
+// The specialization for size 8.
+template <>
+class TypeWithSize<8> {
+ public:
+#if GTEST_OS_WINDOWS
+ typedef __int64 Int;
+ typedef unsigned __int64 UInt;
+#else
+ typedef long long Int; // NOLINT
+ typedef unsigned long long UInt; // NOLINT
+#endif // GTEST_OS_WINDOWS
+};
+
+// Integer types of known sizes.
+typedef TypeWithSize<4>::Int Int32;
+typedef TypeWithSize<4>::UInt UInt32;
+typedef TypeWithSize<8>::Int Int64;
+typedef TypeWithSize<8>::UInt UInt64;
+typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
+
+// Utilities for command line flags and environment variables.
+
+// Macro for referencing flags.
+#define GTEST_FLAG(name) FLAGS_gtest_##name
+
+// Macros for declaring flags.
+#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
+#define GTEST_DECLARE_int32_(name) \
+ GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
+#define GTEST_DECLARE_string_(name) \
+ GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name)
+
+// Macros for defining flags.
+#define GTEST_DEFINE_bool_(name, default_val, doc) \
+ GTEST_API_ bool GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_int32_(name, default_val, doc) \
+ GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
+#define GTEST_DEFINE_string_(name, default_val, doc) \
+ GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val)
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes the result
+// to *value and returns true; otherwise leaves *value unchanged and returns
+// false.
+// TODO(chandlerc): Find a better way to refactor flag and environment parsing
+// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
+// function.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value);
+
+// Parses a bool/Int32/string from the environment variable
+// corresponding to the given Google Test flag.
+bool BoolFromGTestEnv(const char* flag, bool default_val);
+GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
+const char* StringFromGTestEnv(const char* flag, const char* default_val);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-string.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-string.h
new file mode 100644
index 000000000..aff093dec
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-string.h
@@ -0,0 +1,350 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file declares the String class and functions used internally by
+// Google Test. They are subject to change without notice. They should not used
+// by code external to Google Test.
+//
+// This header file is #included by <gtest/internal/gtest-internal.h>.
+// It should not be #included by other files.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
+
+#ifdef __BORLANDC__
+// string.h is not guaranteed to provide strcpy on C++ Builder.
+#include <mem.h>
+#endif
+
+#include <string.h>
+#include <gtest/internal/gtest-port.h>
+
+#include <string>
+
+namespace testing {
+namespace internal {
+
+// String - a UTF-8 string class.
+//
+// For historic reasons, we don't use std::string.
+//
+// TODO(wan@google.com): replace this class with std::string or
+// implement it in terms of the latter.
+//
+// Note that String can represent both NULL and the empty string,
+// while std::string cannot represent NULL.
+//
+// NULL and the empty string are considered different. NULL is less
+// than anything (including the empty string) except itself.
+//
+// This class only provides minimum functionality necessary for
+// implementing Google Test. We do not intend to implement a full-fledged
+// string class here.
+//
+// Since the purpose of this class is to provide a substitute for
+// std::string on platforms where it cannot be used, we define a copy
+// constructor and assignment operators such that we don't need
+// conditional compilation in a lot of places.
+//
+// In order to make the representation efficient, the d'tor of String
+// is not virtual. Therefore DO NOT INHERIT FROM String.
+class GTEST_API_ String {
+ public:
+ // Static utility methods
+
+ // Returns the input enclosed in double quotes if it's not NULL;
+ // otherwise returns "(null)". For example, "\"Hello\"" is returned
+ // for input "Hello".
+ //
+ // This is useful for printing a C string in the syntax of a literal.
+ //
+ // Known issue: escape sequences are not handled yet.
+ static String ShowCStringQuoted(const char* c_str);
+
+ // Clones a 0-terminated C string, allocating memory using new. The
+ // caller is responsible for deleting the return value using
+ // delete[]. Returns the cloned string, or NULL if the input is
+ // NULL.
+ //
+ // This is different from strdup() in string.h, which allocates
+ // memory using malloc().
+ static const char* CloneCString(const char* c_str);
+
+#if GTEST_OS_WINDOWS_MOBILE
+ // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
+ // able to pass strings to Win32 APIs on CE we need to convert them
+ // to 'Unicode', UTF-16.
+
+ // Creates a UTF-16 wide string from the given ANSI string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the wide string, or NULL if the
+ // input is NULL.
+ //
+ // The wide string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static LPCWSTR AnsiToUtf16(const char* c_str);
+
+ // Creates an ANSI string from the given wide string, allocating
+ // memory using new. The caller is responsible for deleting the return
+ // value using delete[]. Returns the ANSI string, or NULL if the
+ // input is NULL.
+ //
+ // The returned string is created using the ANSI codepage (CP_ACP) to
+ // match the behaviour of the ANSI versions of Win32 calls and the
+ // C runtime.
+ static const char* Utf16ToAnsi(LPCWSTR utf16_str);
+#endif
+
+ // Compares two C strings. Returns true iff they have the same content.
+ //
+ // Unlike strcmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CStringEquals(const char* lhs, const char* rhs);
+
+ // Converts a wide C string to a String using the UTF-8 encoding.
+ // NULL will be converted to "(null)". If an error occurred during
+ // the conversion, "(failed to convert from wide string)" is
+ // returned.
+ static String ShowWideCString(const wchar_t* wide_c_str);
+
+ // Similar to ShowWideCString(), except that this function encloses
+ // the converted string in double quotes.
+ static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
+
+ // Compares two wide C strings. Returns true iff they have the same
+ // content.
+ //
+ // Unlike wcscmp(), this function can handle NULL argument(s). A
+ // NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
+
+ // Compares two C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike strcasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL C string,
+ // including the empty string.
+ static bool CaseInsensitiveCStringEquals(const char* lhs,
+ const char* rhs);
+
+ // Compares two wide C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+ static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs);
+
+ // Formats a list of arguments to a String, using the same format
+ // spec string as for printf.
+ //
+ // We do not use the StringPrintf class as it is not universally
+ // available.
+ //
+ // The result is limited to 4096 characters (including the tailing
+ // 0). If 4096 characters are not enough to format the input,
+ // "<buffer exceeded>" is returned.
+ static String Format(const char* format, ...);
+
+ // C'tors
+
+ // The default c'tor constructs a NULL string.
+ String() : c_str_(NULL), length_(0) {}
+
+ // Constructs a String by cloning a 0-terminated C string.
+ String(const char* a_c_str) { // NOLINT
+ if (a_c_str == NULL) {
+ c_str_ = NULL;
+ length_ = 0;
+ } else {
+ ConstructNonNull(a_c_str, strlen(a_c_str));
+ }
+ }
+
+ // Constructs a String by copying a given number of chars from a
+ // buffer. E.g. String("hello", 3) creates the string "hel",
+ // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "",
+ // and String(NULL, 1) results in access violation.
+ String(const char* buffer, size_t a_length) {
+ ConstructNonNull(buffer, a_length);
+ }
+
+ // The copy c'tor creates a new copy of the string. The two
+ // String objects do not share content.
+ String(const String& str) : c_str_(NULL), length_(0) { *this = str; }
+
+ // D'tor. String is intended to be a final class, so the d'tor
+ // doesn't need to be virtual.
+ ~String() { delete[] c_str_; }
+
+ // Allows a String to be implicitly converted to an ::std::string or
+ // ::string, and vice versa. Converting a String containing a NULL
+ // pointer to ::std::string or ::string is undefined behavior.
+ // Converting a ::std::string or ::string containing an embedded NUL
+ // character to a String will result in the prefix up to the first
+ // NUL character.
+ String(const ::std::string& str) {
+ ConstructNonNull(str.c_str(), str.length());
+ }
+
+ operator ::std::string() const { return ::std::string(c_str(), length()); }
+
+#if GTEST_HAS_GLOBAL_STRING
+ String(const ::string& str) {
+ ConstructNonNull(str.c_str(), str.length());
+ }
+
+ operator ::string() const { return ::string(c_str(), length()); }
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ // Returns true iff this is an empty string (i.e. "").
+ bool empty() const { return (c_str() != NULL) && (length() == 0); }
+
+ // Compares this with another String.
+ // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+ // if this is greater than rhs.
+ int Compare(const String& rhs) const;
+
+ // Returns true iff this String equals the given C string. A NULL
+ // string and a non-NULL string are considered not equal.
+ bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; }
+
+ // Returns true iff this String is less than the given String. A
+ // NULL string is considered less than "".
+ bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
+
+ // Returns true iff this String doesn't equal the given C string. A NULL
+ // string and a non-NULL string are considered not equal.
+ bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); }
+
+ // Returns true iff this String ends with the given suffix. *Any*
+ // String is considered to end with a NULL or empty suffix.
+ bool EndsWith(const char* suffix) const;
+
+ // Returns true iff this String ends with the given suffix, not considering
+ // case. Any String is considered to end with a NULL or empty suffix.
+ bool EndsWithCaseInsensitive(const char* suffix) const;
+
+ // Returns the length of the encapsulated string, or 0 if the
+ // string is NULL.
+ size_t length() const { return length_; }
+
+ // Gets the 0-terminated C string this String object represents.
+ // The String object still owns the string. Therefore the caller
+ // should NOT delete the return value.
+ const char* c_str() const { return c_str_; }
+
+ // Assigns a C string to this object. Self-assignment works.
+ const String& operator=(const char* a_c_str) {
+ return *this = String(a_c_str);
+ }
+
+ // Assigns a String object to this object. Self-assignment works.
+ const String& operator=(const String& rhs) {
+ if (this != &rhs) {
+ delete[] c_str_;
+ if (rhs.c_str() == NULL) {
+ c_str_ = NULL;
+ length_ = 0;
+ } else {
+ ConstructNonNull(rhs.c_str(), rhs.length());
+ }
+ }
+
+ return *this;
+ }
+
+ private:
+ // Constructs a non-NULL String from the given content. This
+ // function can only be called when data_ has not been allocated.
+ // ConstructNonNull(NULL, 0) results in an empty string ("").
+ // ConstructNonNull(NULL, non_zero) is undefined behavior.
+ void ConstructNonNull(const char* buffer, size_t a_length) {
+ char* const str = new char[a_length + 1];
+ memcpy(str, buffer, a_length);
+ str[a_length] = '\0';
+ c_str_ = str;
+ length_ = a_length;
+ }
+
+ const char* c_str_;
+ size_t length_;
+}; // class String
+
+// Streams a String to an ostream. Each '\0' character in the String
+// is replaced with "\\0".
+inline ::std::ostream& operator<<(::std::ostream& os, const String& str) {
+ if (str.c_str() == NULL) {
+ os << "(null)";
+ } else {
+ const char* const c_str = str.c_str();
+ for (size_t i = 0; i != str.length(); i++) {
+ if (c_str[i] == '\0') {
+ os << "\\0";
+ } else {
+ os << c_str[i];
+ }
+ }
+ }
+ return os;
+}
+
+// Gets the content of the StrStream's buffer as a String. Each '\0'
+// character in the buffer is replaced with "\\0".
+GTEST_API_ String StrStreamToString(StrStream* stream);
+
+// Converts a streamable value to a String. A NULL pointer is
+// converted to "(null)". When the input value is a ::string,
+// ::std::string, ::wstring, or ::std::wstring object, each NUL
+// character in it is replaced with "\\0".
+
+// Declared here but defined in gtest.h, so that it has access
+// to the definition of the Message class, required by the ARM
+// compiler.
+template <typename T>
+String StreamableToString(const T& streamable);
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-tuple.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-tuple.h
new file mode 100644
index 000000000..16178fc07
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-tuple.h
@@ -0,0 +1,968 @@
+// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
+
+// Copyright 2009 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+
+#include <utility> // For ::std::pair.
+
+// The compiler used in Symbian has a bug that prevents us from declaring the
+// tuple template as a friend (it complains that tuple is redefined). This
+// hack bypasses the bug by declaring the members that should otherwise be
+// private as public.
+// Sun Studio versions < 12 also have the above bug.
+#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+#define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
+#else
+#define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
+ template <GTEST_10_TYPENAMES_(U)> friend class tuple; \
+ private:
+#endif
+
+// GTEST_n_TUPLE_(T) is the type of an n-tuple.
+#define GTEST_0_TUPLE_(T) tuple<>
+#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
+ void, void, void>
+#define GTEST_2_TUPLE_(T) tuple<T##0, T##1, void, void, void, void, void, \
+ void, void, void>
+#define GTEST_3_TUPLE_(T) tuple<T##0, T##1, T##2, void, void, void, void, \
+ void, void, void>
+#define GTEST_4_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, void, void, void, \
+ void, void, void>
+#define GTEST_5_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, void, void, \
+ void, void, void>
+#define GTEST_6_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, void, \
+ void, void, void>
+#define GTEST_7_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ void, void, void>
+#define GTEST_8_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, void, void>
+#define GTEST_9_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, T##8, void>
+#define GTEST_10_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
+ T##7, T##8, T##9>
+
+// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
+#define GTEST_0_TYPENAMES_(T)
+#define GTEST_1_TYPENAMES_(T) typename T##0
+#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1
+#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2
+#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3
+#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4
+#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5
+#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6
+#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, typename T##7
+#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, \
+ typename T##7, typename T##8
+#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
+ typename T##3, typename T##4, typename T##5, typename T##6, \
+ typename T##7, typename T##8, typename T##9
+
+// In theory, defining stuff in the ::std namespace is undefined
+// behavior. We can do this as we are playing the role of a standard
+// library vendor.
+namespace std {
+namespace tr1 {
+
+template <typename T0 = void, typename T1 = void, typename T2 = void,
+ typename T3 = void, typename T4 = void, typename T5 = void,
+ typename T6 = void, typename T7 = void, typename T8 = void,
+ typename T9 = void>
+class tuple;
+
+// Anything in namespace gtest_internal is Google Test's INTERNAL
+// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
+namespace gtest_internal {
+
+// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
+template <typename T>
+struct ByRef { typedef const T& type; }; // NOLINT
+template <typename T>
+struct ByRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for ByRef.
+#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
+
+// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
+// is the same as tr1::add_reference<T>::type.
+template <typename T>
+struct AddRef { typedef T& type; }; // NOLINT
+template <typename T>
+struct AddRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for AddRef.
+#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
+
+// A helper for implementing get<k>().
+template <int k> class Get;
+
+// A helper for implementing tuple_element<k, T>. kIndexValid is true
+// iff k < the number of fields in tuple type T.
+template <bool kIndexValid, int kIndex, class Tuple>
+struct TupleElement;
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 0, GTEST_10_TUPLE_(T)> { typedef T0 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 1, GTEST_10_TUPLE_(T)> { typedef T1 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 2, GTEST_10_TUPLE_(T)> { typedef T2 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 3, GTEST_10_TUPLE_(T)> { typedef T3 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 4, GTEST_10_TUPLE_(T)> { typedef T4 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 5, GTEST_10_TUPLE_(T)> { typedef T5 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 6, GTEST_10_TUPLE_(T)> { typedef T6 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 7, GTEST_10_TUPLE_(T)> { typedef T7 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 8, GTEST_10_TUPLE_(T)> { typedef T8 type; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct TupleElement<true, 9, GTEST_10_TUPLE_(T)> { typedef T9 type; };
+
+} // namespace gtest_internal
+
+template <>
+class tuple<> {
+ public:
+ tuple() {}
+ tuple(const tuple& /* t */) {}
+ tuple& operator=(const tuple& /* t */) { return *this; }
+};
+
+template <GTEST_1_TYPENAMES_(T)>
+class GTEST_1_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {}
+
+ tuple(const tuple& t) : f0_(t.f0_) {}
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_1_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_1_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ return *this;
+ }
+
+ T0 f0_;
+};
+
+template <GTEST_2_TYPENAMES_(T)>
+class GTEST_2_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0),
+ f1_(f1) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {}
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {}
+ template <typename U0, typename U1>
+ tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_2_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+ template <typename U0, typename U1>
+ tuple& operator=(const ::std::pair<U0, U1>& p) {
+ f0_ = p.first;
+ f1_ = p.second;
+ return *this;
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_2_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+};
+
+template <GTEST_3_TYPENAMES_(T)>
+class GTEST_3_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_3_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_3_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+};
+
+template <GTEST_4_TYPENAMES_(T)>
+class GTEST_4_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {}
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_4_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_4_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+};
+
+template <GTEST_5_TYPENAMES_(T)>
+class GTEST_5_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3,
+ GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_) {}
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_5_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_5_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+};
+
+template <GTEST_6_TYPENAMES_(T)>
+class GTEST_6_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_) {}
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_6_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_6_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+};
+
+template <GTEST_7_TYPENAMES_(T)>
+class GTEST_7_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3), f4_(f4), f5_(f5), f6_(f6) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_7_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_7_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+};
+
+template <GTEST_8_TYPENAMES_(T)>
+class GTEST_8_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6,
+ GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5), f6_(f6), f7_(f7) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_8_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_8_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+};
+
+template <GTEST_9_TYPENAMES_(T)>
+class GTEST_9_TUPLE_(T) {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+ GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
+ f5_(f5), f6_(f6), f7_(f7), f8_(f8) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_9_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_9_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ f8_ = t.f8_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+ T8 f8_;
+};
+
+template <GTEST_10_TYPENAMES_(T)>
+class tuple {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(),
+ f9_() {}
+
+ explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
+ GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
+ GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
+ GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2),
+ f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {}
+
+ tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
+ f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {}
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
+ f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_),
+ f9_(t.f9_) {}
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_10_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_10_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) {
+ f0_ = t.f0_;
+ f1_ = t.f1_;
+ f2_ = t.f2_;
+ f3_ = t.f3_;
+ f4_ = t.f4_;
+ f5_ = t.f5_;
+ f6_ = t.f6_;
+ f7_ = t.f7_;
+ f8_ = t.f8_;
+ f9_ = t.f9_;
+ return *this;
+ }
+
+ T0 f0_;
+ T1 f1_;
+ T2 f2_;
+ T3 f3_;
+ T4 f4_;
+ T5 f5_;
+ T6 f6_;
+ T7 f7_;
+ T8 f8_;
+ T9 f9_;
+};
+
+// 6.1.3.2 Tuple creation functions.
+
+// Known limitations: we don't support passing an
+// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
+// implement tie().
+
+inline tuple<> make_tuple() { return tuple<>(); }
+
+template <GTEST_1_TYPENAMES_(T)>
+inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) {
+ return GTEST_1_TUPLE_(T)(f0);
+}
+
+template <GTEST_2_TYPENAMES_(T)>
+inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) {
+ return GTEST_2_TUPLE_(T)(f0, f1);
+}
+
+template <GTEST_3_TYPENAMES_(T)>
+inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) {
+ return GTEST_3_TUPLE_(T)(f0, f1, f2);
+}
+
+template <GTEST_4_TYPENAMES_(T)>
+inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3) {
+ return GTEST_4_TUPLE_(T)(f0, f1, f2, f3);
+}
+
+template <GTEST_5_TYPENAMES_(T)>
+inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4) {
+ return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4);
+}
+
+template <GTEST_6_TYPENAMES_(T)>
+inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5) {
+ return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5);
+}
+
+template <GTEST_7_TYPENAMES_(T)>
+inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6) {
+ return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6);
+}
+
+template <GTEST_8_TYPENAMES_(T)>
+inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) {
+ return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7);
+}
+
+template <GTEST_9_TYPENAMES_(T)>
+inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+ const T8& f8) {
+ return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8);
+}
+
+template <GTEST_10_TYPENAMES_(T)>
+inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
+ const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
+ const T8& f8, const T9& f9) {
+ return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);
+}
+
+// 6.1.3.3 Tuple helper classes.
+
+template <typename Tuple> struct tuple_size;
+
+template <GTEST_0_TYPENAMES_(T)>
+struct tuple_size<GTEST_0_TUPLE_(T)> { static const int value = 0; };
+
+template <GTEST_1_TYPENAMES_(T)>
+struct tuple_size<GTEST_1_TUPLE_(T)> { static const int value = 1; };
+
+template <GTEST_2_TYPENAMES_(T)>
+struct tuple_size<GTEST_2_TUPLE_(T)> { static const int value = 2; };
+
+template <GTEST_3_TYPENAMES_(T)>
+struct tuple_size<GTEST_3_TUPLE_(T)> { static const int value = 3; };
+
+template <GTEST_4_TYPENAMES_(T)>
+struct tuple_size<GTEST_4_TUPLE_(T)> { static const int value = 4; };
+
+template <GTEST_5_TYPENAMES_(T)>
+struct tuple_size<GTEST_5_TUPLE_(T)> { static const int value = 5; };
+
+template <GTEST_6_TYPENAMES_(T)>
+struct tuple_size<GTEST_6_TUPLE_(T)> { static const int value = 6; };
+
+template <GTEST_7_TYPENAMES_(T)>
+struct tuple_size<GTEST_7_TUPLE_(T)> { static const int value = 7; };
+
+template <GTEST_8_TYPENAMES_(T)>
+struct tuple_size<GTEST_8_TUPLE_(T)> { static const int value = 8; };
+
+template <GTEST_9_TYPENAMES_(T)>
+struct tuple_size<GTEST_9_TUPLE_(T)> { static const int value = 9; };
+
+template <GTEST_10_TYPENAMES_(T)>
+struct tuple_size<GTEST_10_TUPLE_(T)> { static const int value = 10; };
+
+template <int k, class Tuple>
+struct tuple_element {
+ typedef typename gtest_internal::TupleElement<
+ k < (tuple_size<Tuple>::value), k, Tuple>::type type;
+};
+
+#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
+
+// 6.1.3.4 Element access.
+
+namespace gtest_internal {
+
+template <>
+class Get<0> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+ Field(Tuple& t) { return t.f0_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
+ ConstField(const Tuple& t) { return t.f0_; }
+};
+
+template <>
+class Get<1> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+ Field(Tuple& t) { return t.f1_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
+ ConstField(const Tuple& t) { return t.f1_; }
+};
+
+template <>
+class Get<2> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+ Field(Tuple& t) { return t.f2_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
+ ConstField(const Tuple& t) { return t.f2_; }
+};
+
+template <>
+class Get<3> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+ Field(Tuple& t) { return t.f3_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
+ ConstField(const Tuple& t) { return t.f3_; }
+};
+
+template <>
+class Get<4> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+ Field(Tuple& t) { return t.f4_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
+ ConstField(const Tuple& t) { return t.f4_; }
+};
+
+template <>
+class Get<5> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+ Field(Tuple& t) { return t.f5_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
+ ConstField(const Tuple& t) { return t.f5_; }
+};
+
+template <>
+class Get<6> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+ Field(Tuple& t) { return t.f6_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
+ ConstField(const Tuple& t) { return t.f6_; }
+};
+
+template <>
+class Get<7> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+ Field(Tuple& t) { return t.f7_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
+ ConstField(const Tuple& t) { return t.f7_; }
+};
+
+template <>
+class Get<8> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+ Field(Tuple& t) { return t.f8_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
+ ConstField(const Tuple& t) { return t.f8_; }
+};
+
+template <>
+class Get<9> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+ Field(Tuple& t) { return t.f9_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
+ ConstField(const Tuple& t) { return t.f9_; }
+};
+
+} // namespace gtest_internal
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
+get(GTEST_10_TUPLE_(T)& t) {
+ return gtest_internal::Get<k>::Field(t);
+}
+
+template <int k, GTEST_10_TYPENAMES_(T)>
+GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
+get(const GTEST_10_TUPLE_(T)& t) {
+ return gtest_internal::Get<k>::ConstField(t);
+}
+
+// 6.1.3.5 Relational operators
+
+// We only implement == and !=, as we don't have a need for the rest yet.
+
+namespace gtest_internal {
+
+// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
+// first k fields of t1 equals the first k fields of t2.
+// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
+// k1 != k2.
+template <int kSize1, int kSize2>
+struct SameSizeTuplePrefixComparator;
+
+template <>
+struct SameSizeTuplePrefixComparator<0, 0> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
+ return true;
+ }
+};
+
+template <int k>
+struct SameSizeTuplePrefixComparator<k, k> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& t1, const Tuple2& t2) {
+ return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
+ ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
+ }
+};
+
+} // namespace gtest_internal
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator==(const GTEST_10_TUPLE_(T)& t,
+ const GTEST_10_TUPLE_(U)& u) {
+ return gtest_internal::SameSizeTuplePrefixComparator<
+ tuple_size<GTEST_10_TUPLE_(T)>::value,
+ tuple_size<GTEST_10_TUPLE_(U)>::value>::Eq(t, u);
+}
+
+template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
+inline bool operator!=(const GTEST_10_TUPLE_(T)& t,
+ const GTEST_10_TUPLE_(U)& u) { return !(t == u); }
+
+// 6.1.4 Pairs.
+// Unimplemented.
+
+} // namespace tr1
+} // namespace std
+
+#undef GTEST_0_TUPLE_
+#undef GTEST_1_TUPLE_
+#undef GTEST_2_TUPLE_
+#undef GTEST_3_TUPLE_
+#undef GTEST_4_TUPLE_
+#undef GTEST_5_TUPLE_
+#undef GTEST_6_TUPLE_
+#undef GTEST_7_TUPLE_
+#undef GTEST_8_TUPLE_
+#undef GTEST_9_TUPLE_
+#undef GTEST_10_TUPLE_
+
+#undef GTEST_0_TYPENAMES_
+#undef GTEST_1_TYPENAMES_
+#undef GTEST_2_TYPENAMES_
+#undef GTEST_3_TYPENAMES_
+#undef GTEST_4_TYPENAMES_
+#undef GTEST_5_TYPENAMES_
+#undef GTEST_6_TYPENAMES_
+#undef GTEST_7_TYPENAMES_
+#undef GTEST_8_TYPENAMES_
+#undef GTEST_9_TYPENAMES_
+#undef GTEST_10_TYPENAMES_
+
+#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
+#undef GTEST_BY_REF_
+#undef GTEST_ADD_REF_
+#undef GTEST_TUPLE_ELEMENT_
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-tuple.h.pump b/Source/ThirdParty/gtest/include/gtest/internal/gtest-tuple.h.pump
new file mode 100644
index 000000000..85ebc8062
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-tuple.h.pump
@@ -0,0 +1,336 @@
+$$ -*- mode: c++; -*-
+$var n = 10 $$ Maximum number of tuple fields we want to support.
+$$ This meta comment fixes auto-indentation in Emacs. }}
+// Copyright 2009 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
+
+#include <utility> // For ::std::pair.
+
+// The compiler used in Symbian has a bug that prevents us from declaring the
+// tuple template as a friend (it complains that tuple is redefined). This
+// hack bypasses the bug by declaring the members that should otherwise be
+// private as public.
+// Sun Studio versions < 12 also have the above bug.
+#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+#define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
+#else
+#define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
+ template <GTEST_$(n)_TYPENAMES_(U)> friend class tuple; \
+ private:
+#endif
+
+
+$range i 0..n-1
+$range j 0..n
+$range k 1..n
+// GTEST_n_TUPLE_(T) is the type of an n-tuple.
+#define GTEST_0_TUPLE_(T) tuple<>
+
+$for k [[
+$range m 0..k-1
+$range m2 k..n-1
+#define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]>
+
+]]
+
+// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
+
+$for j [[
+$range m 0..j-1
+#define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]]
+
+
+]]
+
+// In theory, defining stuff in the ::std namespace is undefined
+// behavior. We can do this as we are playing the role of a standard
+// library vendor.
+namespace std {
+namespace tr1 {
+
+template <$for i, [[typename T$i = void]]>
+class tuple;
+
+// Anything in namespace gtest_internal is Google Test's INTERNAL
+// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
+namespace gtest_internal {
+
+// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
+template <typename T>
+struct ByRef { typedef const T& type; }; // NOLINT
+template <typename T>
+struct ByRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for ByRef.
+#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
+
+// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
+// is the same as tr1::add_reference<T>::type.
+template <typename T>
+struct AddRef { typedef T& type; }; // NOLINT
+template <typename T>
+struct AddRef<T&> { typedef T& type; }; // NOLINT
+
+// A handy wrapper for AddRef.
+#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
+
+// A helper for implementing get<k>().
+template <int k> class Get;
+
+// A helper for implementing tuple_element<k, T>. kIndexValid is true
+// iff k < the number of fields in tuple type T.
+template <bool kIndexValid, int kIndex, class Tuple>
+struct TupleElement;
+
+
+$for i [[
+template <GTEST_$(n)_TYPENAMES_(T)>
+struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T)> [[]]
+{ typedef T$i type; };
+
+
+]]
+} // namespace gtest_internal
+
+template <>
+class tuple<> {
+ public:
+ tuple() {}
+ tuple(const tuple& /* t */) {}
+ tuple& operator=(const tuple& /* t */) { return *this; }
+};
+
+
+$for k [[
+$range m 0..k-1
+template <GTEST_$(k)_TYPENAMES_(T)>
+class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] {
+ public:
+ template <int k> friend class gtest_internal::Get;
+
+ tuple() : $for m, [[f$(m)_()]] {}
+
+ explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]]
+$for m, [[f$(m)_(f$m)]] {}
+
+ tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
+
+ template <GTEST_$(k)_TYPENAMES_(U)>
+ tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
+
+$if k == 2 [[
+ template <typename U0, typename U1>
+ tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
+
+]]
+
+ tuple& operator=(const tuple& t) { return CopyFrom(t); }
+
+ template <GTEST_$(k)_TYPENAMES_(U)>
+ tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) {
+ return CopyFrom(t);
+ }
+
+$if k == 2 [[
+ template <typename U0, typename U1>
+ tuple& operator=(const ::std::pair<U0, U1>& p) {
+ f0_ = p.first;
+ f1_ = p.second;
+ return *this;
+ }
+
+]]
+
+ GTEST_DECLARE_TUPLE_AS_FRIEND_
+
+ template <GTEST_$(k)_TYPENAMES_(U)>
+ tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) {
+
+$for m [[
+ f$(m)_ = t.f$(m)_;
+
+]]
+ return *this;
+ }
+
+
+$for m [[
+ T$m f$(m)_;
+
+]]
+};
+
+
+]]
+// 6.1.3.2 Tuple creation functions.
+
+// Known limitations: we don't support passing an
+// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
+// implement tie().
+
+inline tuple<> make_tuple() { return tuple<>(); }
+
+$for k [[
+$range m 0..k-1
+
+template <GTEST_$(k)_TYPENAMES_(T)>
+inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) {
+ return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]);
+}
+
+]]
+
+// 6.1.3.3 Tuple helper classes.
+
+template <typename Tuple> struct tuple_size;
+
+
+$for j [[
+template <GTEST_$(j)_TYPENAMES_(T)>
+struct tuple_size<GTEST_$(j)_TUPLE_(T)> { static const int value = $j; };
+
+
+]]
+template <int k, class Tuple>
+struct tuple_element {
+ typedef typename gtest_internal::TupleElement<
+ k < (tuple_size<Tuple>::value), k, Tuple>::type type;
+};
+
+#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
+
+// 6.1.3.4 Element access.
+
+namespace gtest_internal {
+
+
+$for i [[
+template <>
+class Get<$i> {
+ public:
+ template <class Tuple>
+ static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
+ Field(Tuple& t) { return t.f$(i)_; } // NOLINT
+
+ template <class Tuple>
+ static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
+ ConstField(const Tuple& t) { return t.f$(i)_; }
+};
+
+
+]]
+} // namespace gtest_internal
+
+template <int k, GTEST_$(n)_TYPENAMES_(T)>
+GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
+get(GTEST_$(n)_TUPLE_(T)& t) {
+ return gtest_internal::Get<k>::Field(t);
+}
+
+template <int k, GTEST_$(n)_TYPENAMES_(T)>
+GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
+get(const GTEST_$(n)_TUPLE_(T)& t) {
+ return gtest_internal::Get<k>::ConstField(t);
+}
+
+// 6.1.3.5 Relational operators
+
+// We only implement == and !=, as we don't have a need for the rest yet.
+
+namespace gtest_internal {
+
+// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
+// first k fields of t1 equals the first k fields of t2.
+// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
+// k1 != k2.
+template <int kSize1, int kSize2>
+struct SameSizeTuplePrefixComparator;
+
+template <>
+struct SameSizeTuplePrefixComparator<0, 0> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
+ return true;
+ }
+};
+
+template <int k>
+struct SameSizeTuplePrefixComparator<k, k> {
+ template <class Tuple1, class Tuple2>
+ static bool Eq(const Tuple1& t1, const Tuple2& t2) {
+ return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
+ ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
+ }
+};
+
+} // namespace gtest_internal
+
+template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
+inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t,
+ const GTEST_$(n)_TUPLE_(U)& u) {
+ return gtest_internal::SameSizeTuplePrefixComparator<
+ tuple_size<GTEST_$(n)_TUPLE_(T)>::value,
+ tuple_size<GTEST_$(n)_TUPLE_(U)>::value>::Eq(t, u);
+}
+
+template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
+inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t,
+ const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); }
+
+// 6.1.4 Pairs.
+// Unimplemented.
+
+} // namespace tr1
+} // namespace std
+
+
+$for j [[
+#undef GTEST_$(j)_TUPLE_
+
+]]
+
+
+$for j [[
+#undef GTEST_$(j)_TYPENAMES_
+
+]]
+
+#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
+#undef GTEST_BY_REF_
+#undef GTEST_ADD_REF_
+#undef GTEST_TUPLE_ELEMENT_
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-type-util.h b/Source/ThirdParty/gtest/include/gtest/internal/gtest-type-util.h
new file mode 100644
index 000000000..093eee6f0
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-type-util.h
@@ -0,0 +1,3321 @@
+// This file was GENERATED by command:
+// pump.py gtest-type-util.h.pump
+// DO NOT EDIT BY HAND!!!
+
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently we support at most 50 types in a list, and at most 50
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework@googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include <gtest/internal/gtest-port.h>
+#include <gtest/internal/gtest-string.h>
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+#ifdef __GLIBCXX__
+#include <cxxabi.h>
+#endif // __GLIBCXX__
+
+namespace testing {
+namespace internal {
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type. This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+ typedef bool type;
+};
+
+// GetTypeName<T>() returns a human-readable name of type T.
+template <typename T>
+String GetTypeName() {
+#if GTEST_HAS_RTTI
+
+ const char* const name = typeid(T).name();
+#ifdef __GLIBCXX__
+ int status = 0;
+ // gcc's implementation of typeid(T).name() mangles the type name,
+ // so we have to demangle it.
+ char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status);
+ const String name_str(status == 0 ? readable_name : name);
+ free(readable_name);
+ return name_str;
+#else
+ return name;
+#endif // __GLIBCXX__
+
+#else
+ return "<type>";
+#endif // GTEST_HAS_RTTI
+}
+
+// A unique type used as the default value for the arguments of class
+// template Types. This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists. In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+ typedef T1 Head;
+ typedef Types0 Tail;
+};
+template <typename T1, typename T2>
+struct Types2 {
+ typedef T1 Head;
+ typedef Types1<T2> Tail;
+};
+
+template <typename T1, typename T2, typename T3>
+struct Types3 {
+ typedef T1 Head;
+ typedef Types2<T2, T3> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types4 {
+ typedef T1 Head;
+ typedef Types3<T2, T3, T4> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types5 {
+ typedef T1 Head;
+ typedef Types4<T2, T3, T4, T5> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+struct Types6 {
+ typedef T1 Head;
+ typedef Types5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+struct Types7 {
+ typedef T1 Head;
+ typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+struct Types8 {
+ typedef T1 Head;
+ typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+struct Types9 {
+ typedef T1 Head;
+ typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types10 {
+ typedef T1 Head;
+ typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+struct Types11 {
+ typedef T1 Head;
+ typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+struct Types12 {
+ typedef T1 Head;
+ typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+struct Types13 {
+ typedef T1 Head;
+ typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+struct Types14 {
+ typedef T1 Head;
+ typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types15 {
+ typedef T1 Head;
+ typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+struct Types16 {
+ typedef T1 Head;
+ typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+struct Types17 {
+ typedef T1 Head;
+ typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+struct Types18 {
+ typedef T1 Head;
+ typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+struct Types19 {
+ typedef T1 Head;
+ typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types20 {
+ typedef T1 Head;
+ typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+struct Types21 {
+ typedef T1 Head;
+ typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+struct Types22 {
+ typedef T1 Head;
+ typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+struct Types23 {
+ typedef T1 Head;
+ typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+struct Types24 {
+ typedef T1 Head;
+ typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types25 {
+ typedef T1 Head;
+ typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+struct Types26 {
+ typedef T1 Head;
+ typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+struct Types27 {
+ typedef T1 Head;
+ typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+struct Types28 {
+ typedef T1 Head;
+ typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+struct Types29 {
+ typedef T1 Head;
+ typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types30 {
+ typedef T1 Head;
+ typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+struct Types31 {
+ typedef T1 Head;
+ typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+struct Types32 {
+ typedef T1 Head;
+ typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+struct Types33 {
+ typedef T1 Head;
+ typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+struct Types34 {
+ typedef T1 Head;
+ typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types35 {
+ typedef T1 Head;
+ typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+struct Types36 {
+ typedef T1 Head;
+ typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+struct Types37 {
+ typedef T1 Head;
+ typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+struct Types38 {
+ typedef T1 Head;
+ typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+struct Types39 {
+ typedef T1 Head;
+ typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types40 {
+ typedef T1 Head;
+ typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+struct Types41 {
+ typedef T1 Head;
+ typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+struct Types42 {
+ typedef T1 Head;
+ typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+struct Types43 {
+ typedef T1 Head;
+ typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+struct Types44 {
+ typedef T1 Head;
+ typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types45 {
+ typedef T1 Head;
+ typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+struct Types46 {
+ typedef T1 Head;
+ typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+struct Types47 {
+ typedef T1 Head;
+ typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+struct Types48 {
+ typedef T1 Head;
+ typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+struct Types49 {
+ typedef T1 Head;
+ typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+struct Types50 {
+ typedef T1 Head;
+ typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+} // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length. Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Types template.
+template <typename T1 = internal::None, typename T2 = internal::None,
+ typename T3 = internal::None, typename T4 = internal::None,
+ typename T5 = internal::None, typename T6 = internal::None,
+ typename T7 = internal::None, typename T8 = internal::None,
+ typename T9 = internal::None, typename T10 = internal::None,
+ typename T11 = internal::None, typename T12 = internal::None,
+ typename T13 = internal::None, typename T14 = internal::None,
+ typename T15 = internal::None, typename T16 = internal::None,
+ typename T17 = internal::None, typename T18 = internal::None,
+ typename T19 = internal::None, typename T20 = internal::None,
+ typename T21 = internal::None, typename T22 = internal::None,
+ typename T23 = internal::None, typename T24 = internal::None,
+ typename T25 = internal::None, typename T26 = internal::None,
+ typename T27 = internal::None, typename T28 = internal::None,
+ typename T29 = internal::None, typename T30 = internal::None,
+ typename T31 = internal::None, typename T32 = internal::None,
+ typename T33 = internal::None, typename T34 = internal::None,
+ typename T35 = internal::None, typename T36 = internal::None,
+ typename T37 = internal::None, typename T38 = internal::None,
+ typename T39 = internal::None, typename T40 = internal::None,
+ typename T41 = internal::None, typename T42 = internal::None,
+ typename T43 = internal::None, typename T44 = internal::None,
+ typename T45 = internal::None, typename T46 = internal::None,
+ typename T47 = internal::None, typename T48 = internal::None,
+ typename T49 = internal::None, typename T50 = internal::None>
+struct Types {
+ typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Types<internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types0 type;
+};
+template <typename T1>
+struct Types<T1, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types1<T1> type;
+};
+template <typename T1, typename T2>
+struct Types<T1, T2, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types2<T1, T2> type;
+};
+template <typename T1, typename T2, typename T3>
+struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types3<T1, T2, T3> type;
+};
+template <typename T1, typename T2, typename T3, typename T4>
+struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types4<T1, T2, T3, T4> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types5<T1, T2, T3, T4, T5> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6>
+struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
+ T12> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
+ T26> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
+ T40> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None, internal::None> {
+ typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None, internal::None> {
+ typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ internal::None, internal::None, internal::None, internal::None,
+ internal::None> {
+ typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, internal::None, internal::None, internal::None, internal::None> {
+ typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, internal::None, internal::None, internal::None> {
+ typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, T48, internal::None, internal::None> {
+ typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49>
+struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
+ T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
+ T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
+ T46, T47, T48, T49, internal::None> {
+ typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+namespace internal {
+
+#define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>. This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+ template <typename T>
+ struct Bind {
+ typedef Tmpl<T> type;
+ };
+};
+
+#define GTEST_BIND_(TmplSel, T) \
+ TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates. This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists. In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN). Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates0 Tail;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates2 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates1<T2> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates3 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates2<T2, T3> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4>
+struct Templates4 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates3<T2, T3, T4> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates5 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates4<T2, T3, T4, T5> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates6 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates5<T2, T3, T4, T5, T6> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7>
+struct Templates7 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates8 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates9 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10>
+struct Templates10 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates11 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates12 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13>
+struct Templates13 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates14 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates15 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16>
+struct Templates16 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates17 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates18 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19>
+struct Templates19 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates20 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates21 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22>
+struct Templates22 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates23 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates24 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25>
+struct Templates25 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates26 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates27 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28>
+struct Templates28 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates29 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates30 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31>
+struct Templates31 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates32 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates33 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34>
+struct Templates34 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates35 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates36 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37>
+struct Templates37 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates38 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates39 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40>
+struct Templates40 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates41 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates42 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43>
+struct Templates43 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates44 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates45 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46>
+struct Templates46 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates47 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates48 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49>
+struct Templates49 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48, T49> Tail;
+};
+
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
+struct Templates50 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
+ T43, T44, T45, T46, T47, T48, T49, T50> Tail;
+};
+
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length. Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Templates template.
+template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
+ GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
+ GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
+ GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
+ GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
+ GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
+ GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
+ GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
+ GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
+ GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
+ GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
+ GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
+ GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
+ GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
+ GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
+ GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
+ GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
+ GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
+ GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
+ GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
+ GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
+ GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
+ GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
+ GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
+ GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
+struct Templates {
+ typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
+};
+
+template <>
+struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates0 type;
+};
+template <GTEST_TEMPLATE_ T1>
+struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates1<T1> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
+struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates2<T1, T2> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
+struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates3<T1, T2, T3> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4>
+struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates4<T1, T2, T3, T4> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
+struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates5<T1, T2, T3, T4, T5> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
+struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates6<T1, T2, T3, T4, T5, T6> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT> {
+ typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT> {
+ typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT> {
+ typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, NoneT, NoneT, NoneT, NoneT> {
+ typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, NoneT, NoneT, NoneT> {
+ typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, T48, NoneT, NoneT> {
+ typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48> type;
+};
+template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
+ GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
+ GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
+ GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
+ GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
+ GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
+ GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
+ GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
+ GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
+ GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
+ GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
+ GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
+ GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
+ GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
+ GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
+ GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
+ GTEST_TEMPLATE_ T49>
+struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
+ T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
+ T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
+ T45, T46, T47, T48, T49, NoneT> {
+ typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
+ T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
+ T42, T43, T44, T45, T46, T47, T48, T49> type;
+};
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList { typedef Types1<T> type; };
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10,
+ typename T11, typename T12, typename T13, typename T14, typename T15,
+ typename T16, typename T17, typename T18, typename T19, typename T20,
+ typename T21, typename T22, typename T23, typename T24, typename T25,
+ typename T26, typename T27, typename T28, typename T29, typename T30,
+ typename T31, typename T32, typename T33, typename T34, typename T35,
+ typename T36, typename T37, typename T38, typename T39, typename T40,
+ typename T41, typename T42, typename T43, typename T44, typename T45,
+ typename T46, typename T47, typename T48, typename T49, typename T50>
+struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
+ T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
+ T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
+ T44, T45, T46, T47, T48, T49, T50> > {
+ typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
+ T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
+ T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
+ T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/Source/ThirdParty/gtest/include/gtest/internal/gtest-type-util.h.pump b/Source/ThirdParty/gtest/include/gtest/internal/gtest-type-util.h.pump
new file mode 100644
index 000000000..5aed1e554
--- /dev/null
+++ b/Source/ThirdParty/gtest/include/gtest/internal/gtest-type-util.h.pump
@@ -0,0 +1,287 @@
+$$ -*- mode: c++; -*-
+$var n = 50 $$ Maximum length of type lists we want to support.
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Type utilities needed for implementing typed and type-parameterized
+// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
+//
+// Currently we support at most $n types in a list, and at most $n
+// type-parameterized tests in one type-parameterized test case.
+// Please contact googletestframework@googlegroups.com if you need
+// more.
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
+
+#include <gtest/internal/gtest-port.h>
+#include <gtest/internal/gtest-string.h>
+
+#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
+// libstdc++ (which is where cxxabi.h comes from).
+#ifdef __GLIBCXX__
+#include <cxxabi.h>
+#endif // __GLIBCXX__
+
+namespace testing {
+namespace internal {
+
+// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
+// type. This can be used as a compile-time assertion to ensure that
+// two types are equal.
+
+template <typename T1, typename T2>
+struct AssertTypeEq;
+
+template <typename T>
+struct AssertTypeEq<T, T> {
+ typedef bool type;
+};
+
+// GetTypeName<T>() returns a human-readable name of type T.
+template <typename T>
+String GetTypeName() {
+#if GTEST_HAS_RTTI
+
+ const char* const name = typeid(T).name();
+#ifdef __GLIBCXX__
+ int status = 0;
+ // gcc's implementation of typeid(T).name() mangles the type name,
+ // so we have to demangle it.
+ char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status);
+ const String name_str(status == 0 ? readable_name : name);
+ free(readable_name);
+ return name_str;
+#else
+ return name;
+#endif // __GLIBCXX__
+
+#else
+ return "<type>";
+#endif // GTEST_HAS_RTTI
+}
+
+// A unique type used as the default value for the arguments of class
+// template Types. This allows us to simulate variadic templates
+// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
+// support directly.
+struct None {};
+
+// The following family of struct and struct templates are used to
+// represent type lists. In particular, TypesN<T1, T2, ..., TN>
+// represents a type list with N types (T1, T2, ..., and TN) in it.
+// Except for Types0, every struct in the family has two member types:
+// Head for the first type in the list, and Tail for the rest of the
+// list.
+
+// The empty type list.
+struct Types0 {};
+
+// Type lists of length 1, 2, 3, and so on.
+
+template <typename T1>
+struct Types1 {
+ typedef T1 Head;
+ typedef Types0 Tail;
+};
+
+$range i 2..n
+
+$for i [[
+$range j 1..i
+$range k 2..i
+template <$for j, [[typename T$j]]>
+struct Types$i {
+ typedef T1 Head;
+ typedef Types$(i-1)<$for k, [[T$k]]> Tail;
+};
+
+
+]]
+
+} // namespace internal
+
+// We don't want to require the users to write TypesN<...> directly,
+// as that would require them to count the length. Types<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Types<int>
+// will appear as Types<int, None, None, ..., None> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Types<T1, ..., TN>, and Google Test will translate
+// that to TypesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Types template.
+
+$range i 1..n
+template <$for i, [[typename T$i = internal::None]]>
+struct Types {
+ typedef internal::Types$n<$for i, [[T$i]]> type;
+};
+
+template <>
+struct Types<$for i, [[internal::None]]> {
+ typedef internal::Types0 type;
+};
+
+$range i 1..n-1
+$for i [[
+$range j 1..i
+$range k i+1..n
+template <$for j, [[typename T$j]]>
+struct Types<$for j, [[T$j]]$for k[[, internal::None]]> {
+ typedef internal::Types$i<$for j, [[T$j]]> type;
+};
+
+]]
+
+namespace internal {
+
+#define GTEST_TEMPLATE_ template <typename T> class
+
+// The template "selector" struct TemplateSel<Tmpl> is used to
+// represent Tmpl, which must be a class template with one type
+// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
+// as the type Tmpl<T>. This allows us to actually instantiate the
+// template "selected" by TemplateSel<Tmpl>.
+//
+// This trick is necessary for simulating typedef for class templates,
+// which C++ doesn't support directly.
+template <GTEST_TEMPLATE_ Tmpl>
+struct TemplateSel {
+ template <typename T>
+ struct Bind {
+ typedef Tmpl<T> type;
+ };
+};
+
+#define GTEST_BIND_(TmplSel, T) \
+ TmplSel::template Bind<T>::type
+
+// A unique struct template used as the default value for the
+// arguments of class template Templates. This allows us to simulate
+// variadic templates (e.g. Templates<int>, Templates<int, double>,
+// and etc), which C++ doesn't support directly.
+template <typename T>
+struct NoneT {};
+
+// The following family of struct and struct templates are used to
+// represent template lists. In particular, TemplatesN<T1, T2, ...,
+// TN> represents a list of N templates (T1, T2, ..., and TN). Except
+// for Templates0, every struct in the family has two member types:
+// Head for the selector of the first template in the list, and Tail
+// for the rest of the list.
+
+// The empty template list.
+struct Templates0 {};
+
+// Template lists of length 1, 2, 3, and so on.
+
+template <GTEST_TEMPLATE_ T1>
+struct Templates1 {
+ typedef TemplateSel<T1> Head;
+ typedef Templates0 Tail;
+};
+
+$range i 2..n
+
+$for i [[
+$range j 1..i
+$range k 2..i
+template <$for j, [[GTEST_TEMPLATE_ T$j]]>
+struct Templates$i {
+ typedef TemplateSel<T1> Head;
+ typedef Templates$(i-1)<$for k, [[T$k]]> Tail;
+};
+
+
+]]
+
+// We don't want to require the users to write TemplatesN<...> directly,
+// as that would require them to count the length. Templates<...> is much
+// easier to write, but generates horrible messages when there is a
+// compiler error, as gcc insists on printing out each template
+// argument, even if it has the default value (this means Templates<list>
+// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
+// errors).
+//
+// Our solution is to combine the best part of the two approaches: a
+// user would write Templates<T1, ..., TN>, and Google Test will translate
+// that to TemplatesN<T1, ..., TN> internally to make error messages
+// readable. The translation is done by the 'type' member of the
+// Templates template.
+
+$range i 1..n
+template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]>
+struct Templates {
+ typedef Templates$n<$for i, [[T$i]]> type;
+};
+
+template <>
+struct Templates<$for i, [[NoneT]]> {
+ typedef Templates0 type;
+};
+
+$range i 1..n-1
+$for i [[
+$range j 1..i
+$range k i+1..n
+template <$for j, [[GTEST_TEMPLATE_ T$j]]>
+struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> {
+ typedef Templates$i<$for j, [[T$j]]> type;
+};
+
+]]
+
+// The TypeList template makes it possible to use either a single type
+// or a Types<...> list in TYPED_TEST_CASE() and
+// INSTANTIATE_TYPED_TEST_CASE_P().
+
+template <typename T>
+struct TypeList { typedef Types1<T> type; };
+
+
+$range i 1..n
+template <$for i, [[typename T$i]]>
+struct TypeList<Types<$for i, [[T$i]]> > {
+ typedef typename Types<$for i, [[T$i]]>::type type;
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
diff --git a/Source/ThirdParty/gtest/m4/acx_pthread.m4 b/Source/ThirdParty/gtest/m4/acx_pthread.m4
new file mode 100644
index 000000000..2cf20de14
--- /dev/null
+++ b/Source/ThirdParty/gtest/m4/acx_pthread.m4
@@ -0,0 +1,363 @@
+# This was retrieved from
+# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?revision=1277&root=avahi
+# See also (perhaps for new versions?)
+# http://svn.0pointer.de/viewvc/trunk/common/acx_pthread.m4?root=avahi
+#
+# We've rewritten the inconsistency check code (from avahi), to work
+# more broadly. In particular, it no longer assumes ld accepts -zdefs.
+# This caused a restructing of the code, but the functionality has only
+# changed a little.
+
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl @summary figure out how to build C programs using POSIX threads
+dnl
+dnl This macro figures out how to build C programs using POSIX threads.
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
+dnl C compiler flags that are needed. (The user can also force certain
+dnl compiler flags/libs to be tested by setting these environment
+dnl variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well. e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+dnl $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to use
+dnl these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl LIBS="$PTHREAD_LIBS $LIBS"
+dnl CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
+dnl default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform, or
+dnl if you have any other suggestions or comments. This macro was based
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
+dnl We are also grateful for the helpful feedback of numerous users.
+dnl
+dnl @category InstalledPackages
+dnl @author Steven G. Johnson <stevenj@alum.mit.edu>
+dnl @version 2006-05-29
+dnl @license GPLWithACException
+dnl
+dnl Checks for GCC shared/pthread inconsistency based on work by
+dnl Marcin Owsiany <marcin@owsiany.pl>
+
+
+AC_DEFUN([ACX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important. Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+
+ acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+ ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+
+ pthread-config)
+ AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+ if test x"$acx_pthread_config" = xno; then continue; fi
+ PTHREAD_CFLAGS="`pthread-config --cflags`"
+ PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+ ;;
+
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+ # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+ AC_MSG_CHECKING([for joinable pthread attribute])
+ attr_name=unknown
+ for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+ AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+ [attr_name=$attr; break])
+ done
+ AC_MSG_RESULT($attr_name)
+ if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+ AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+ [Define to necessary symbol if this constant
+ uses a non-standard name on your system.])
+ fi
+
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+ *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ # More AIX lossage: must compile with xlc_r or cc_r
+ if test x"$GCC" != xyes; then
+ AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+ else
+ PTHREAD_CC=$CC
+ fi
+
+ # The next part tries to detect GCC inconsistency with -shared on some
+ # architectures and systems. The problem is that in certain
+ # configurations, when -shared is specified, GCC "forgets" to
+ # internally use various flags which are still necessary.
+
+ #
+ # Prepare the flags
+ #
+ save_CFLAGS="$CFLAGS"
+ save_LIBS="$LIBS"
+ save_CC="$CC"
+
+ # Try with the flags determined by the earlier checks.
+ #
+ # -Wl,-z,defs forces link-time symbol resolution, so that the
+ # linking checks with -shared actually have any value
+ #
+ # FIXME: -fPIC is required for -shared on many architectures,
+ # so we specify it here, but the right way would probably be to
+ # properly detect whether it is actually required.
+ CFLAGS="-shared -fPIC -Wl,-z,defs $CFLAGS $PTHREAD_CFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CC="$PTHREAD_CC"
+
+ # In order not to create several levels of indentation, we test
+ # the value of "$done" until we find the cure or run out of ideas.
+ done="no"
+
+ # First, make sure the CFLAGS we added are actually accepted by our
+ # compiler. If not (and OS X's ld, for instance, does not accept -z),
+ # then we can't do this test.
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether to check for GCC pthread/shared inconsistencies])
+ AC_TRY_LINK(,, , [done=yes])
+
+ if test "x$done" = xyes ; then
+ AC_MSG_RESULT([no])
+ else
+ AC_MSG_RESULT([yes])
+ fi
+ fi
+
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -pthread is sufficient with -shared])
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+
+ #
+ # Linux gcc on some architectures such as mips/mipsel forgets
+ # about -lpthread
+ #
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -lpthread fixes that])
+ LIBS="-lpthread $PTHREAD_LIBS $save_LIBS"
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ PTHREAD_LIBS="-lpthread $PTHREAD_LIBS"
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+ #
+ # FreeBSD 4.10 gcc forgets to use -lc_r instead of -lc
+ #
+ if test x"$done" = xno; then
+ AC_MSG_CHECKING([whether -lc_r fixes that])
+ LIBS="-lc_r $PTHREAD_LIBS $save_LIBS"
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [done=yes])
+
+ if test "x$done" = xyes; then
+ AC_MSG_RESULT([yes])
+ PTHREAD_LIBS="-lc_r $PTHREAD_LIBS"
+ else
+ AC_MSG_RESULT([no])
+ fi
+ fi
+ if test x"$done" = xno; then
+ # OK, we have run out of ideas
+ AC_MSG_WARN([Impossible to determine how to use pthreads with shared libraries])
+
+ # so it's not safe to assume that we may use pthreads
+ acx_pthread_ok=no
+ fi
+
+ CFLAGS="$save_CFLAGS"
+ LIBS="$save_LIBS"
+ CC="$save_CC"
+else
+ PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+ :
+else
+ acx_pthread_ok=no
+ $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff --git a/Source/ThirdParty/gtest/m4/gtest.m4 b/Source/ThirdParty/gtest/m4/gtest.m4
new file mode 100644
index 000000000..6598ba75a
--- /dev/null
+++ b/Source/ThirdParty/gtest/m4/gtest.m4
@@ -0,0 +1,74 @@
+dnl GTEST_LIB_CHECK([minimum version [,
+dnl action if found [,action if not found]]])
+dnl
+dnl Check for the presence of the Google Test library, optionally at a minimum
+dnl version, and indicate a viable version with the HAVE_GTEST flag. It defines
+dnl standard variables for substitution including GTEST_CPPFLAGS,
+dnl GTEST_CXXFLAGS, GTEST_LDFLAGS, and GTEST_LIBS. It also defines
+dnl GTEST_VERSION as the version of Google Test found. Finally, it provides
+dnl optional custom action slots in the event GTEST is found or not.
+AC_DEFUN([GTEST_LIB_CHECK],
+[
+dnl Provide a flag to enable or disable Google Test usage.
+AC_ARG_ENABLE([gtest],
+ [AS_HELP_STRING([--enable-gtest],
+ [Enable tests using the Google C++ Testing Framework.
+ (Default is enabled.)])],
+ [],
+ [enable_gtest=])
+AC_ARG_VAR([GTEST_CONFIG],
+ [The exact path of Google Test's 'gtest-config' script.])
+AC_ARG_VAR([GTEST_CPPFLAGS],
+ [C-like preprocessor flags for Google Test.])
+AC_ARG_VAR([GTEST_CXXFLAGS],
+ [C++ compile flags for Google Test.])
+AC_ARG_VAR([GTEST_LDFLAGS],
+ [Linker path and option flags for Google Test.])
+AC_ARG_VAR([GTEST_LIBS],
+ [Library linking flags for Google Test.])
+AC_ARG_VAR([GTEST_VERSION],
+ [The version of Google Test available.])
+HAVE_GTEST="no"
+AS_IF([test "x${enable_gtest}" != "xno"],
+ [AC_MSG_CHECKING([for 'gtest-config'])
+ AS_IF([test "x${enable_gtest}" != "xyes"],
+ [AS_IF([test -x "${enable_gtest}/scripts/gtest-config"],
+ [GTEST_CONFIG="${enable_gtest}/scripts/gtest-config"],
+ [GTEST_CONFIG="${enable_gtest}/bin/gtest-config"])
+ AS_IF([test -x "${GTEST_CONFIG}"], [],
+ [AC_MSG_RESULT([no])
+ AC_MSG_ERROR([dnl
+Unable to locate either a built or installed Google Test.
+The specific location '${enable_gtest}' was provided for a built or installed
+Google Test, but no 'gtest-config' script could be found at this location.])
+ ])],
+ [AC_PATH_PROG([GTEST_CONFIG], [gtest-config])])
+ AS_IF([test -x "${GTEST_CONFIG}"],
+ [AC_MSG_RESULT([${GTEST_CONFIG}])
+ m4_ifval([$1],
+ [_gtest_min_version="--min-version=$1"
+ AC_MSG_CHECKING([for Google Test at least version >= $1])],
+ [_gtest_min_version="--min-version=0"
+ AC_MSG_CHECKING([for Google Test])])
+ AS_IF([${GTEST_CONFIG} ${_gtest_min_version}],
+ [AC_MSG_RESULT([yes])
+ HAVE_GTEST='yes'],
+ [AC_MSG_RESULT([no])])],
+ [AC_MSG_RESULT([no])])
+ AS_IF([test "x${HAVE_GTEST}" = "xyes"],
+ [GTEST_CPPFLAGS=`${GTEST_CONFIG} --cppflags`
+ GTEST_CXXFLAGS=`${GTEST_CONFIG} --cxxflags`
+ GTEST_LDFLAGS=`${GTEST_CONFIG} --ldflags`
+ GTEST_LIBS=`${GTEST_CONFIG} --libs`
+ GTEST_VERSION=`${GTEST_CONFIG} --version`
+ AC_DEFINE([HAVE_GTEST],[1],[Defined when Google Test is available.])],
+ [AS_IF([test "x${enable_gtest}" = "xyes"],
+ [AC_MSG_ERROR([dnl
+Google Test was enabled, but no viable version could be found.])
+ ])])])
+AC_SUBST([HAVE_GTEST])
+AM_CONDITIONAL([HAVE_GTEST],[test "x$HAVE_GTEST" = "xyes"])
+AS_IF([test "x$HAVE_GTEST" = "xyes"],
+ [m4_ifval([$2], [$2])],
+ [m4_ifval([$3], [$3])])
+])
diff --git a/Source/ThirdParty/gtest/make/Makefile b/Source/ThirdParty/gtest/make/Makefile
new file mode 100644
index 000000000..5b27b6a2c
--- /dev/null
+++ b/Source/ThirdParty/gtest/make/Makefile
@@ -0,0 +1,80 @@
+# A sample Makefile for building Google Test and using it in user
+# tests. Please tweak it to suit your environment and project. You
+# may want to move it to your project's root directory.
+#
+# SYNOPSIS:
+#
+# make [all] - makes everything.
+# make TARGET - makes the given target.
+# make clean - removes all files generated by make.
+
+# Please tweak the following variable definitions as needed by your
+# project, except GTEST_HEADERS, which you can use in your own targets
+# but shouldn't modify.
+
+# Points to the root of Google Test, relative to where this file is.
+# Remember to tweak this if you move this file.
+GTEST_DIR = ..
+
+# Where to find user code.
+USER_DIR = ../samples
+
+# Flags passed to the preprocessor.
+CPPFLAGS += -I$(GTEST_DIR)/include
+
+# Flags passed to the C++ compiler.
+CXXFLAGS += -g -Wall -Wextra
+
+# All tests produced by this Makefile. Remember to add new tests you
+# created to the list.
+TESTS = sample1_unittest
+
+# All Google Test headers. Usually you shouldn't change this
+# definition.
+GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
+ $(GTEST_DIR)/include/gtest/internal/*.h
+
+# House-keeping build targets.
+
+all : $(TESTS)
+
+clean :
+ rm -f $(TESTS) gtest.a gtest_main.a *.o
+
+# Builds gtest.a and gtest_main.a.
+
+# Usually you shouldn't tweak such internal variables, indicated by a
+# trailing _.
+GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)
+
+# For simplicity and to avoid depending on Google Test's
+# implementation details, the dependencies specified below are
+# conservative and not optimized. This is fine as Google Test
+# compiles fast and for ordinary users its source rarely changes.
+gtest-all.o : $(GTEST_SRCS_)
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
+ $(GTEST_DIR)/src/gtest-all.cc
+
+gtest_main.o : $(GTEST_SRCS_)
+ $(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
+ $(GTEST_DIR)/src/gtest_main.cc
+
+gtest.a : gtest-all.o
+ $(AR) $(ARFLAGS) $@ $^
+
+gtest_main.a : gtest-all.o gtest_main.o
+ $(AR) $(ARFLAGS) $@ $^
+
+# Builds a sample test. A test should link with either gtest.a or
+# gtest_main.a, depending on whether it defines its own main()
+# function.
+
+sample1.o : $(USER_DIR)/sample1.cc $(USER_DIR)/sample1.h $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1.cc
+
+sample1_unittest.o : $(USER_DIR)/sample1_unittest.cc \
+ $(USER_DIR)/sample1.h $(GTEST_HEADERS)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/sample1_unittest.cc
+
+sample1_unittest : sample1.o sample1_unittest.o gtest_main.a
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@
diff --git a/Source/ThirdParty/gtest/msvc/gtest-md.sln b/Source/ThirdParty/gtest/msvc/gtest-md.sln
new file mode 100644
index 000000000..829b4019a
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest-md.sln
@@ -0,0 +1,45 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-md", "gtest-md.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main-md", "gtest_main-md.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862033}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test-md", "gtest_prod_test-md.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest-md", "gtest_unittest-md.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A2}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.ActiveCfg = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug.Build.0 = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.ActiveCfg = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release.Build.0 = Release|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.ActiveCfg = Debug|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862033}.Debug.Build.0 = Debug|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.ActiveCfg = Release|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862033}.Release.Build.0 = Release|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.ActiveCfg = Debug|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Debug.Build.0 = Debug|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.ActiveCfg = Release|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}.Release.Build.0 = Release|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.ActiveCfg = Debug|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Debug.Build.0 = Debug|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.ActiveCfg = Release|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A2}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/Source/ThirdParty/gtest/msvc/gtest-md.vcproj b/Source/ThirdParty/gtest/msvc/gtest-md.vcproj
new file mode 100644
index 000000000..6c987e9c3
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest-md.vcproj
@@ -0,0 +1,777 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="gtest-md"
+ ProjectGUID="{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}"
+ RootNamespace="gtest-md"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationBuildDir)\lib"
+ IntermediateDirectory="$(ConfigurationBuildDir)\obj\$(ProjectName)"
+ ConfigurationType="4"
+ InheritedPropertySheets="&quot;$(ProjectDir)\..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops&quot;"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\gtest.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationBuildDir)\lib"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(ProjectDir)\..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\gtest.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_Cairo_CFLite|Win32"
+ OutputDirectory="$(ConfigurationBuildDir)\lib"
+ IntermediateDirectory="$(ConfigurationBuildDir)\obj\$(ProjectName)"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(ProjectDir)\..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\gtest.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_Cairo_CFLite|Win32"
+ OutputDirectory="$(ConfigurationBuildDir)\lib"
+ IntermediateDirectory="$(ConfigurationBuildDir)\obj\$(ProjectName)"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(ProjectDir)\..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\gtest.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Production|Win32"
+ OutputDirectory="$(ConfigurationBuildDir)\lib"
+ IntermediateDirectory="$(ConfigurationBuildDir)\obj\$(ProjectName)"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(ProjectDir)\..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\gtest.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ OutputDirectory="$(ConfigurationBuildDir)\lib"
+ IntermediateDirectory="$(ConfigurationBuildDir)\obj\$(ProjectName)"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(ProjectDir)\..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="false"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)\gtest.lib"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\src\gtest-death-test.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest-filepath.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest-port.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest-test-part.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest-typed-test.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest.cc"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Production|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath="..\include\gtest\internal\gtest-death-test-internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-death-test.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-filepath.h"
+ >
+ </File>
+ <File
+ RelativePath="..\src\gtest-internal-inl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-internal.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-port.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-spi.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-string.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest_pred_impl.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest_prod.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/gtest/msvc/gtest.sln b/Source/ThirdParty/gtest/msvc/gtest.sln
new file mode 100644
index 000000000..c1b292964
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest.sln
@@ -0,0 +1,45 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest", "gtest.vcproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_main", "gtest_main.vcproj", "{3AF54C8A-10BF-4332-9147-F68ED9862032}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_unittest", "gtest_unittest.vcproj", "{4D9FDFB5-986A-4139-823C-F4EE0ED481A1}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest_prod_test", "gtest_prod_test.vcproj", "{24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.ActiveCfg = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Debug.Build.0 = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.ActiveCfg = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}.Release.Build.0 = Release|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.ActiveCfg = Debug|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862032}.Debug.Build.0 = Debug|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.ActiveCfg = Release|Win32
+ {3AF54C8A-10BF-4332-9147-F68ED9862032}.Release.Build.0 = Release|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.ActiveCfg = Debug|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Debug.Build.0 = Debug|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.ActiveCfg = Release|Win32
+ {4D9FDFB5-986A-4139-823C-F4EE0ED481A1}.Release.Build.0 = Release|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.ActiveCfg = Debug|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Debug.Build.0 = Debug|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.ActiveCfg = Release|Win32
+ {24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/Source/ThirdParty/gtest/msvc/gtest.vcproj b/Source/ThirdParty/gtest/msvc/gtest.vcproj
new file mode 100644
index 000000000..c4ca609ed
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest.vcproj
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest"
+ ProjectGUID="{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/gtestd.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="&quot;..\include&quot;;&quot;..&quot;">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/gtest.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\src\gtest-death-test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest-filepath.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest-test-part.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest-port.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest-typed-test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\src\gtest.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\include\gtest\internal\gtest-death-test-internal.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-death-test.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-filepath.h">
+ </File>
+ <File
+ RelativePath="..\src\gtest-internal-inl.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-internal.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-message.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-port.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-spi.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-string.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest_pred_impl.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest_prod.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/gtest/msvc/gtest_main-md.vcproj b/Source/ThirdParty/gtest/msvc/gtest_main-md.vcproj
new file mode 100644
index 000000000..0f92f2244
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest_main-md.vcproj
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_main-md"
+ ProjectGUID="{3AF54C8A-10BF-4332-9147-F68ED9862033}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName)d.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="&quot;..\include&quot;;&quot;..&quot;">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName).lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}"
+ Name="gtest-md"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\src\gtest_main.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\include\gtest\internal\gtest-death-test-internal.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-death-test.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-filepath.h">
+ </File>
+ <File
+ RelativePath="..\src\gtest-internal-inl.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-internal.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-message.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-port.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-spi.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-string.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest_pred_impl.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest_prod.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/gtest/msvc/gtest_main.vcproj b/Source/ThirdParty/gtest/msvc/gtest_main.vcproj
new file mode 100644
index 000000000..24058c8fe
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest_main.vcproj
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_main"
+ ProjectGUID="{3AF54C8A-10BF-4332-9147-F68ED9862032}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName)d.lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ ReferencesPath="&quot;..\include&quot;;&quot;..&quot;">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile="$(OutDir)/$(ProjectName).lib"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{C8F6C172-56F2-4E76-B5FA-C3B423B31BE7}"
+ Name="gtest"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\src\gtest_main.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\include\gtest\internal\gtest-death-test-internal.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-death-test.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-filepath.h">
+ </File>
+ <File
+ RelativePath="..\src\gtest-internal-inl.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-internal.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-message.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-port.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest-spi.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\internal\gtest-string.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest_pred_impl.h">
+ </File>
+ <File
+ RelativePath="..\include\gtest\gtest_prod.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/gtest/msvc/gtest_prod_test-md.vcproj b/Source/ThirdParty/gtest/msvc/gtest_prod_test-md.vcproj
new file mode 100644
index 000000000..4071d28fe
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest_prod_test-md.vcproj
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_prod_test-md"
+ ProjectGUID="{24848551-EF4F-47E8-9A9D-EA4D49BC3ECB}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_prod_test.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/gtest_prod_test.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_prod_test.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{3AF54C8A-10BF-4332-9147-F68ED9862033}"
+ Name="gtest_main-md"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\test\gtest_prod_test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\test\production.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\test\production.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/gtest/msvc/gtest_prod_test.vcproj b/Source/ThirdParty/gtest/msvc/gtest_prod_test.vcproj
new file mode 100644
index 000000000..998c75808
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest_prod_test.vcproj
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_prod_test"
+ ProjectGUID="{24848551-EF4F-47E8-9A9D-EA4D49BC3ECA}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_prod_test.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/gtest_prod_test.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_prod_test.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{3AF54C8A-10BF-4332-9147-F68ED9862032}"
+ Name="gtest_main"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\test\gtest_prod_test.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\test\production.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ <File
+ RelativePath="..\test\production.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/gtest/msvc/gtest_unittest-md.vcproj b/Source/ThirdParty/gtest/msvc/gtest_unittest-md.vcproj
new file mode 100644
index 000000000..152593975
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest_unittest-md.vcproj
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_unittest-md"
+ ProjectGUID="{4D9FDFB5-986A-4139-823C-F4EE0ED481A2}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_unittest.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/gtest_unittest.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_unittest.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{3AF54C8A-10BF-4332-9147-F68ED9862033}"
+ Name="gtest_main-md"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\test\gtest_unittest.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ BasicRuntimeChecks="0"
+ UsePrecompiledHeader="0"
+ DebugInformationFormat="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/gtest/msvc/gtest_unittest.vcproj b/Source/ThirdParty/gtest/msvc/gtest_unittest.vcproj
new file mode 100644
index 000000000..2b2d74345
--- /dev/null
+++ b/Source/ThirdParty/gtest/msvc/gtest_unittest.vcproj
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="gtest_unittest"
+ ProjectGUID="{4D9FDFB5-986A-4139-823C-F4EE0ED481A1}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_unittest.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/gtest_unittest.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionName)/$(ConfigurationName)"
+ IntermediateDirectory="$(OutDir)/$(ProjectName)"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="4"
+ UsePrecompiledHeader="3"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="FALSE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)/gtest_unittest.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ <ProjectReference
+ ReferencedProjectIdentifier="{3AF54C8A-10BF-4332-9147-F68ED9862032}"
+ Name="gtest_main"/>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+ <File
+ RelativePath="..\test\gtest_unittest.cc">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ BasicRuntimeChecks="0"
+ UsePrecompiledHeader="0"
+ DebugInformationFormat="3"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;..&quot;;&quot;..\include&quot;"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Source/ThirdParty/gtest/run_tests.py b/Source/ThirdParty/gtest/run_tests.py
new file mode 100755
index 000000000..e1084056e
--- /dev/null
+++ b/Source/ThirdParty/gtest/run_tests.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Runs the specified tests for Google Test.
+
+This script requires Python 2.3 or higher. To learn the usage, run it
+with -h.
+"""
+
+import os
+import sys
+
+SCRIPT_DIR = os.path.dirname(__file__) or '.'
+
+sys.path.append(os.path.join(SCRIPT_DIR, 'test'))
+import run_tests_util
+
+
+def _Main():
+ """Runs all tests for Google Test."""
+
+ options, args = run_tests_util.ParseArgs('gtest')
+ test_runner = run_tests_util.TestRunner(script_dir=SCRIPT_DIR)
+ tests = test_runner.GetTestsToRun(args,
+ options.configurations,
+ options.built_configurations)
+ if not tests:
+ sys.exit(1) # Incorrect parameters given, abort execution.
+
+ sys.exit(test_runner.RunTests(tests[0], tests[1]))
+
+if __name__ == '__main__':
+ _Main()
diff --git a/Source/ThirdParty/gtest/samples/prime_tables.h b/Source/ThirdParty/gtest/samples/prime_tables.h
new file mode 100644
index 000000000..92ce16a01
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/prime_tables.h
@@ -0,0 +1,123 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+// Author: vladl@google.com (Vlad Losev)
+
+// This provides interface PrimeTable that determines whether a number is a
+// prime and determines a next prime number. This interface is used
+// in Google Test samples demonstrating use of parameterized tests.
+
+#ifndef GTEST_SAMPLES_PRIME_TABLES_H_
+#define GTEST_SAMPLES_PRIME_TABLES_H_
+
+#include <algorithm>
+
+// The prime table interface.
+class PrimeTable {
+ public:
+ virtual ~PrimeTable() {}
+
+ // Returns true iff n is a prime number.
+ virtual bool IsPrime(int n) const = 0;
+
+ // Returns the smallest prime number greater than p; or returns -1
+ // if the next prime is beyond the capacity of the table.
+ virtual int GetNextPrime(int p) const = 0;
+};
+
+// Implementation #1 calculates the primes on-the-fly.
+class OnTheFlyPrimeTable : public PrimeTable {
+ public:
+ virtual bool IsPrime(int n) const {
+ if (n <= 1) return false;
+
+ for (int i = 2; i*i <= n; i++) {
+ // n is divisible by an integer other than 1 and itself.
+ if ((n % i) == 0) return false;
+ }
+
+ return true;
+ }
+
+ virtual int GetNextPrime(int p) const {
+ for (int n = p + 1; n > 0; n++) {
+ if (IsPrime(n)) return n;
+ }
+
+ return -1;
+ }
+};
+
+// Implementation #2 pre-calculates the primes and stores the result
+// in an array.
+class PreCalculatedPrimeTable : public PrimeTable {
+ public:
+ // 'max' specifies the maximum number the prime table holds.
+ explicit PreCalculatedPrimeTable(int max)
+ : is_prime_size_(max + 1), is_prime_(new bool[max + 1]) {
+ CalculatePrimesUpTo(max);
+ }
+ virtual ~PreCalculatedPrimeTable() { delete[] is_prime_; }
+
+ virtual bool IsPrime(int n) const {
+ return 0 <= n && n < is_prime_size_ && is_prime_[n];
+ }
+
+ virtual int GetNextPrime(int p) const {
+ for (int n = p + 1; n < is_prime_size_; n++) {
+ if (is_prime_[n]) return n;
+ }
+
+ return -1;
+ }
+
+ private:
+ void CalculatePrimesUpTo(int max) {
+ ::std::fill(is_prime_, is_prime_ + is_prime_size_, true);
+ is_prime_[0] = is_prime_[1] = false;
+
+ for (int i = 2; i <= max; i++) {
+ if (!is_prime_[i]) continue;
+
+ // Marks all multiples of i (except i itself) as non-prime.
+ for (int j = 2*i; j <= max; j += i) {
+ is_prime_[j] = false;
+ }
+ }
+ }
+
+ const int is_prime_size_;
+ bool* const is_prime_;
+
+ // Disables compiler warning "assignment operator could not be generated."
+ void operator=(const PreCalculatedPrimeTable& rhs);
+};
+
+#endif // GTEST_SAMPLES_PRIME_TABLES_H_
diff --git a/Source/ThirdParty/gtest/samples/sample1.cc b/Source/ThirdParty/gtest/samples/sample1.cc
new file mode 100644
index 000000000..f171e2609
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample1.cc
@@ -0,0 +1,68 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include "sample1.h"
+
+// Returns n! (the factorial of n). For negative n, n! is defined to be 1.
+int Factorial(int n) {
+ int result = 1;
+ for (int i = 1; i <= n; i++) {
+ result *= i;
+ }
+
+ return result;
+}
+
+// Returns true iff n is a prime number.
+bool IsPrime(int n) {
+ // Trivial case 1: small numbers
+ if (n <= 1) return false;
+
+ // Trivial case 2: even numbers
+ if (n % 2 == 0) return n == 2;
+
+ // Now, we have that n is odd and n >= 3.
+
+ // Try to divide n by every odd number i, starting from 3
+ for (int i = 3; ; i += 2) {
+ // We only have to try i up to the squre root of n
+ if (i > n/i) break;
+
+ // Now, we have i <= n/i < n.
+ // If n is divisible by i, n is not prime.
+ if (n % i == 0) return false;
+ }
+
+ // n has no integer factor in the range (1, n), and thus is prime.
+ return true;
+}
diff --git a/Source/ThirdParty/gtest/samples/sample1.h b/Source/ThirdParty/gtest/samples/sample1.h
new file mode 100644
index 000000000..3dfeb98c4
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample1.h
@@ -0,0 +1,43 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_SAMPLES_SAMPLE1_H_
+#define GTEST_SAMPLES_SAMPLE1_H_
+
+// Returns n! (the factorial of n). For negative n, n! is defined to be 1.
+int Factorial(int n);
+
+// Returns true iff n is a prime number.
+bool IsPrime(int n);
+
+#endif // GTEST_SAMPLES_SAMPLE1_H_
diff --git a/Source/ThirdParty/gtest/samples/sample10_unittest.cc b/Source/ThirdParty/gtest/samples/sample10_unittest.cc
new file mode 100644
index 000000000..3ad6fd653
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample10_unittest.cc
@@ -0,0 +1,145 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// This sample shows how to use Google Test listener API to implement
+// a primitive leak checker.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <gtest/gtest.h>
+
+using ::testing::EmptyTestEventListener;
+using ::testing::InitGoogleTest;
+using ::testing::Test;
+using ::testing::TestCase;
+using ::testing::TestEventListeners;
+using ::testing::TestInfo;
+using ::testing::TestPartResult;
+using ::testing::UnitTest;
+
+namespace {
+
+// We will track memory used by this class.
+class Water {
+ public:
+ // Normal Water declarations go here.
+
+ // operator new and operator delete help us control water allocation.
+ void* operator new(size_t allocation_size) {
+ allocated_++;
+ return malloc(allocation_size);
+ }
+
+ void operator delete(void* block, size_t /* allocation_size */) {
+ allocated_--;
+ free(block);
+ }
+
+ static int allocated() { return allocated_; }
+
+ private:
+ static int allocated_;
+};
+
+int Water::allocated_ = 0;
+
+// This event listener monitors how many Water objects are created and
+// destroyed by each test, and reports a failure if a test leaks some Water
+// objects. It does this by comparing the number of live Water objects at
+// the beginning of a test and at the end of a test.
+class LeakChecker : public EmptyTestEventListener {
+ private:
+ // Called before a test starts.
+ virtual void OnTestStart(const TestInfo& /* test_info */) {
+ initially_allocated_ = Water::allocated();
+ }
+
+ // Called after a test ends.
+ virtual void OnTestEnd(const TestInfo& /* test_info */) {
+ int difference = Water::allocated() - initially_allocated_;
+
+ // You can generate a failure in any event handler except
+ // OnTestPartResult. Just use an appropriate Google Test assertion to do
+ // it.
+ EXPECT_TRUE(difference <= 0)
+ << "Leaked " << difference << " unit(s) of Water!";
+ }
+
+ int initially_allocated_;
+};
+
+TEST(ListenersTest, DoesNotLeak) {
+ Water* water = new Water;
+ delete water;
+}
+
+// This should fail when the --check_for_leaks command line flag is
+// specified.
+TEST(ListenersTest, LeaksWater) {
+ Water* water = new Water;
+ EXPECT_TRUE(water != NULL);
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ InitGoogleTest(&argc, argv);
+
+ bool check_for_leaks = false;
+ if (argc > 1 && strcmp(argv[1], "--check_for_leaks") == 0 )
+ check_for_leaks = true;
+ else
+ printf("%s\n", "Run this program with --check_for_leaks to enable "
+ "custom leak checking in the tests.");
+
+ // If we are given the --check_for_leaks command line flag, installs the
+ // leak checker.
+ if (check_for_leaks) {
+ TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
+
+ // Adds the leak checker to the end of the test event listener list,
+ // after the default text output printer and the default XML report
+ // generator.
+ //
+ // The order is important - it ensures that failures generated in the
+ // leak checker's OnTestEnd() method are processed by the text and XML
+ // printers *before* their OnTestEnd() methods are called, such that
+ // they are attributed to the right test. Remember that a listener
+ // receives an OnXyzStart event *after* listeners preceding it in the
+ // list received that event, and receives an OnXyzEnd event *before*
+ // listeners preceding it.
+ //
+ // We don't need to worry about deleting the new listener later, as
+ // Google Test will do it.
+ listeners.Append(new LeakChecker);
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/samples/sample1_unittest.cc b/Source/ThirdParty/gtest/samples/sample1_unittest.cc
new file mode 100644
index 000000000..01eb5462f
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample1_unittest.cc
@@ -0,0 +1,153 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+
+// This sample shows how to write a simple unit test for a function,
+// using Google C++ testing framework.
+//
+// Writing a unit test using Google C++ testing framework is easy as 1-2-3:
+
+
+// Step 1. Include necessary header files such that the stuff your
+// test logic needs is declared.
+//
+// Don't forget gtest.h, which declares the testing framework.
+
+#include <limits.h>
+#include "sample1.h"
+#include <gtest/gtest.h>
+
+
+// Step 2. Use the TEST macro to define your tests.
+//
+// TEST has two parameters: the test case name and the test name.
+// After using the macro, you should define your test logic between a
+// pair of braces. You can use a bunch of macros to indicate the
+// success or failure of a test. EXPECT_TRUE and EXPECT_EQ are
+// examples of such macros. For a complete list, see gtest.h.
+//
+// <TechnicalDetails>
+//
+// In Google Test, tests are grouped into test cases. This is how we
+// keep test code organized. You should put logically related tests
+// into the same test case.
+//
+// The test case name and the test name should both be valid C++
+// identifiers. And you should not use underscore (_) in the names.
+//
+// Google Test guarantees that each test you define is run exactly
+// once, but it makes no guarantee on the order the tests are
+// executed. Therefore, you should write your tests in such a way
+// that their results don't depend on their order.
+//
+// </TechnicalDetails>
+
+
+// Tests Factorial().
+
+// Tests factorial of negative numbers.
+TEST(FactorialTest, Negative) {
+ // This test is named "Negative", and belongs to the "FactorialTest"
+ // test case.
+ EXPECT_EQ(1, Factorial(-5));
+ EXPECT_EQ(1, Factorial(-1));
+ EXPECT_TRUE(Factorial(-10) > 0);
+
+ // <TechnicalDetails>
+ //
+ // EXPECT_EQ(expected, actual) is the same as
+ //
+ // EXPECT_TRUE((expected) == (actual))
+ //
+ // except that it will print both the expected value and the actual
+ // value when the assertion fails. This is very helpful for
+ // debugging. Therefore in this case EXPECT_EQ is preferred.
+ //
+ // On the other hand, EXPECT_TRUE accepts any Boolean expression,
+ // and is thus more general.
+ //
+ // </TechnicalDetails>
+}
+
+// Tests factorial of 0.
+TEST(FactorialTest, Zero) {
+ EXPECT_EQ(1, Factorial(0));
+}
+
+// Tests factorial of positive numbers.
+TEST(FactorialTest, Positive) {
+ EXPECT_EQ(1, Factorial(1));
+ EXPECT_EQ(2, Factorial(2));
+ EXPECT_EQ(6, Factorial(3));
+ EXPECT_EQ(40320, Factorial(8));
+}
+
+
+// Tests IsPrime()
+
+// Tests negative input.
+TEST(IsPrimeTest, Negative) {
+ // This test belongs to the IsPrimeTest test case.
+
+ EXPECT_FALSE(IsPrime(-1));
+ EXPECT_FALSE(IsPrime(-2));
+ EXPECT_FALSE(IsPrime(INT_MIN));
+}
+
+// Tests some trivial cases.
+TEST(IsPrimeTest, Trivial) {
+ EXPECT_FALSE(IsPrime(0));
+ EXPECT_FALSE(IsPrime(1));
+ EXPECT_TRUE(IsPrime(2));
+ EXPECT_TRUE(IsPrime(3));
+}
+
+// Tests positive input.
+TEST(IsPrimeTest, Positive) {
+ EXPECT_FALSE(IsPrime(4));
+ EXPECT_TRUE(IsPrime(5));
+ EXPECT_FALSE(IsPrime(6));
+ EXPECT_TRUE(IsPrime(23));
+}
+
+// Step 3. Call RUN_ALL_TESTS() in main().
+//
+// We do this by linking in src/gtest_main.cc file, which consists of
+// a main() function which calls RUN_ALL_TESTS() for us.
+//
+// This runs all the tests you've defined, prints the result, and
+// returns 0 if successful, or 1 otherwise.
+//
+// Did you notice that we didn't register the tests? The
+// RUN_ALL_TESTS() macro magically knows about all the tests we
+// defined. Isn't this convenient?
diff --git a/Source/ThirdParty/gtest/samples/sample2.cc b/Source/ThirdParty/gtest/samples/sample2.cc
new file mode 100644
index 000000000..5f763b9bd
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample2.cc
@@ -0,0 +1,56 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include "sample2.h"
+
+#include <string.h>
+
+// Clones a 0-terminated C string, allocating memory using new.
+const char* MyString::CloneCString(const char* a_c_string) {
+ if (a_c_string == NULL) return NULL;
+
+ const size_t len = strlen(a_c_string);
+ char* const clone = new char[ len + 1 ];
+ memcpy(clone, a_c_string, len + 1);
+
+ return clone;
+}
+
+// Sets the 0-terminated C string this MyString object
+// represents.
+void MyString::Set(const char* a_c_string) {
+ // Makes sure this works when c_string == c_string_
+ const char* const temp = MyString::CloneCString(a_c_string);
+ delete[] c_string_;
+ c_string_ = temp;
+}
diff --git a/Source/ThirdParty/gtest/samples/sample2.h b/Source/ThirdParty/gtest/samples/sample2.h
new file mode 100644
index 000000000..5b57e6082
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample2.h
@@ -0,0 +1,86 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_SAMPLES_SAMPLE2_H_
+#define GTEST_SAMPLES_SAMPLE2_H_
+
+#include <string.h>
+
+
+// A simple string class.
+class MyString {
+ private:
+ const char* c_string_;
+ const MyString& operator=(const MyString& rhs);
+
+ public:
+
+ // Clones a 0-terminated C string, allocating memory using new.
+ static const char* CloneCString(const char* a_c_string);
+
+ ////////////////////////////////////////////////////////////
+ //
+ // C'tors
+
+ // The default c'tor constructs a NULL string.
+ MyString() : c_string_(NULL) {}
+
+ // Constructs a MyString by cloning a 0-terminated C string.
+ explicit MyString(const char* a_c_string) : c_string_(NULL) {
+ Set(a_c_string);
+ }
+
+ // Copy c'tor
+ MyString(const MyString& string) : c_string_(NULL) {
+ Set(string.c_string_);
+ }
+
+ ////////////////////////////////////////////////////////////
+ //
+ // D'tor. MyString is intended to be a final class, so the d'tor
+ // doesn't need to be virtual.
+ ~MyString() { delete[] c_string_; }
+
+ // Gets the 0-terminated C string this MyString object represents.
+ const char* c_string() const { return c_string_; }
+
+ size_t Length() const {
+ return c_string_ == NULL ? 0 : strlen(c_string_);
+ }
+
+ // Sets the 0-terminated C string this MyString object represents.
+ void Set(const char* c_string);
+};
+
+
+#endif // GTEST_SAMPLES_SAMPLE2_H_
diff --git a/Source/ThirdParty/gtest/samples/sample2_unittest.cc b/Source/ThirdParty/gtest/samples/sample2_unittest.cc
new file mode 100644
index 000000000..32232d98c
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample2_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+
+// This sample shows how to write a more complex unit test for a class
+// that has multiple member functions.
+//
+// Usually, it's a good idea to have one test for each method in your
+// class. You don't have to do that exactly, but it helps to keep
+// your tests organized. You may also throw in additional tests as
+// needed.
+
+#include "sample2.h"
+#include <gtest/gtest.h>
+
+// In this example, we test the MyString class (a simple string).
+
+// Tests the default c'tor.
+TEST(MyString, DefaultConstructor) {
+ const MyString s;
+
+ // Asserts that s.c_string() returns NULL.
+ //
+ // <TechnicalDetails>
+ //
+ // If we write NULL instead of
+ //
+ // static_cast<const char *>(NULL)
+ //
+ // in this assertion, it will generate a warning on gcc 3.4. The
+ // reason is that EXPECT_EQ needs to know the types of its
+ // arguments in order to print them when it fails. Since NULL is
+ // #defined as 0, the compiler will use the formatter function for
+ // int to print it. However, gcc thinks that NULL should be used as
+ // a pointer, not an int, and therefore complains.
+ //
+ // The root of the problem is C++'s lack of distinction between the
+ // integer number 0 and the null pointer constant. Unfortunately,
+ // we have to live with this fact.
+ //
+ // </TechnicalDetails>
+ EXPECT_STREQ(NULL, s.c_string());
+
+ EXPECT_EQ(0u, s.Length());
+}
+
+const char kHelloString[] = "Hello, world!";
+
+// Tests the c'tor that accepts a C string.
+TEST(MyString, ConstructorFromCString) {
+ const MyString s(kHelloString);
+ EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0);
+ EXPECT_EQ(sizeof(kHelloString)/sizeof(kHelloString[0]) - 1,
+ s.Length());
+}
+
+// Tests the copy c'tor.
+TEST(MyString, CopyConstructor) {
+ const MyString s1(kHelloString);
+ const MyString s2 = s1;
+ EXPECT_TRUE(strcmp(s2.c_string(), kHelloString) == 0);
+}
+
+// Tests the Set method.
+TEST(MyString, Set) {
+ MyString s;
+
+ s.Set(kHelloString);
+ EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0);
+
+ // Set should work when the input pointer is the same as the one
+ // already in the MyString object.
+ s.Set(s.c_string());
+ EXPECT_TRUE(strcmp(s.c_string(), kHelloString) == 0);
+
+ // Can we set the MyString to NULL?
+ s.Set(NULL);
+ EXPECT_STREQ(NULL, s.c_string());
+}
diff --git a/Source/ThirdParty/gtest/samples/sample3-inl.h b/Source/ThirdParty/gtest/samples/sample3-inl.h
new file mode 100644
index 000000000..46369a076
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample3-inl.h
@@ -0,0 +1,173 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_SAMPLES_SAMPLE3_INL_H_
+#define GTEST_SAMPLES_SAMPLE3_INL_H_
+
+#include <stddef.h>
+
+
+// Queue is a simple queue implemented as a singled-linked list.
+//
+// The element type must support copy constructor.
+template <typename E> // E is the element type
+class Queue;
+
+// QueueNode is a node in a Queue, which consists of an element of
+// type E and a pointer to the next node.
+template <typename E> // E is the element type
+class QueueNode {
+ friend class Queue<E>;
+
+ public:
+ // Gets the element in this node.
+ const E& element() const { return element_; }
+
+ // Gets the next node in the queue.
+ QueueNode* next() { return next_; }
+ const QueueNode* next() const { return next_; }
+
+ private:
+ // Creates a node with a given element value. The next pointer is
+ // set to NULL.
+ QueueNode(const E& an_element) : element_(an_element), next_(NULL) {}
+
+ // We disable the default assignment operator and copy c'tor.
+ const QueueNode& operator = (const QueueNode&);
+ QueueNode(const QueueNode&);
+
+ E element_;
+ QueueNode* next_;
+};
+
+template <typename E> // E is the element type.
+class Queue {
+public:
+
+ // Creates an empty queue.
+ Queue() : head_(NULL), last_(NULL), size_(0) {}
+
+ // D'tor. Clears the queue.
+ ~Queue() { Clear(); }
+
+ // Clears the queue.
+ void Clear() {
+ if (size_ > 0) {
+ // 1. Deletes every node.
+ QueueNode<E>* node = head_;
+ QueueNode<E>* next = node->next();
+ for (; ;) {
+ delete node;
+ node = next;
+ if (node == NULL) break;
+ next = node->next();
+ }
+
+ // 2. Resets the member variables.
+ head_ = last_ = NULL;
+ size_ = 0;
+ }
+ }
+
+ // Gets the number of elements.
+ size_t Size() const { return size_; }
+
+ // Gets the first element of the queue, or NULL if the queue is empty.
+ QueueNode<E>* Head() { return head_; }
+ const QueueNode<E>* Head() const { return head_; }
+
+ // Gets the last element of the queue, or NULL if the queue is empty.
+ QueueNode<E>* Last() { return last_; }
+ const QueueNode<E>* Last() const { return last_; }
+
+ // Adds an element to the end of the queue. A copy of the element is
+ // created using the copy constructor, and then stored in the queue.
+ // Changes made to the element in the queue doesn't affect the source
+ // object, and vice versa.
+ void Enqueue(const E& element) {
+ QueueNode<E>* new_node = new QueueNode<E>(element);
+
+ if (size_ == 0) {
+ head_ = last_ = new_node;
+ size_ = 1;
+ } else {
+ last_->next_ = new_node;
+ last_ = new_node;
+ size_++;
+ }
+ }
+
+ // Removes the head of the queue and returns it. Returns NULL if
+ // the queue is empty.
+ E* Dequeue() {
+ if (size_ == 0) {
+ return NULL;
+ }
+
+ const QueueNode<E>* const old_head = head_;
+ head_ = head_->next_;
+ size_--;
+ if (size_ == 0) {
+ last_ = NULL;
+ }
+
+ E* element = new E(old_head->element());
+ delete old_head;
+
+ return element;
+ }
+
+ // Applies a function/functor on each element of the queue, and
+ // returns the result in a new queue. The original queue is not
+ // affected.
+ template <typename F>
+ Queue* Map(F function) const {
+ Queue* new_queue = new Queue();
+ for (const QueueNode<E>* node = head_; node != NULL; node = node->next_) {
+ new_queue->Enqueue(function(node->element()));
+ }
+
+ return new_queue;
+ }
+
+ private:
+ QueueNode<E>* head_; // The first node of the queue.
+ QueueNode<E>* last_; // The last node of the queue.
+ size_t size_; // The number of elements in the queue.
+
+ // We disallow copying a queue.
+ Queue(const Queue&);
+ const Queue& operator = (const Queue&);
+ };
+
+#endif // GTEST_SAMPLES_SAMPLE3_INL_H_
diff --git a/Source/ThirdParty/gtest/samples/sample3_unittest.cc b/Source/ThirdParty/gtest/samples/sample3_unittest.cc
new file mode 100644
index 000000000..34c1ca865
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample3_unittest.cc
@@ -0,0 +1,151 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+
+// In this example, we use a more advanced feature of Google Test called
+// test fixture.
+//
+// A test fixture is a place to hold objects and functions shared by
+// all tests in a test case. Using a test fixture avoids duplicating
+// the test code necessary to initialize and cleanup those common
+// objects for each test. It is also useful for defining sub-routines
+// that your tests need to invoke a lot.
+//
+// <TechnicalDetails>
+//
+// The tests share the test fixture in the sense of code sharing, not
+// data sharing. Each test is given its own fresh copy of the
+// fixture. You cannot expect the data modified by one test to be
+// passed on to another test, which is a bad idea.
+//
+// The reason for this design is that tests should be independent and
+// repeatable. In particular, a test should not fail as the result of
+// another test's failure. If one test depends on info produced by
+// another test, then the two tests should really be one big test.
+//
+// The macros for indicating the success/failure of a test
+// (EXPECT_TRUE, FAIL, etc) need to know what the current test is
+// (when Google Test prints the test result, it tells you which test
+// each failure belongs to). Technically, these macros invoke a
+// member function of the Test class. Therefore, you cannot use them
+// in a global function. That's why you should put test sub-routines
+// in a test fixture.
+//
+// </TechnicalDetails>
+
+#include "sample3-inl.h"
+#include <gtest/gtest.h>
+
+// To use a test fixture, derive a class from testing::Test.
+class QueueTest : public testing::Test {
+ protected: // You should make the members protected s.t. they can be
+ // accessed from sub-classes.
+
+ // virtual void SetUp() will be called before each test is run. You
+ // should define it if you need to initialize the varaibles.
+ // Otherwise, this can be skipped.
+ virtual void SetUp() {
+ q1_.Enqueue(1);
+ q2_.Enqueue(2);
+ q2_.Enqueue(3);
+ }
+
+ // virtual void TearDown() will be called after each test is run.
+ // You should define it if there is cleanup work to do. Otherwise,
+ // you don't have to provide it.
+ //
+ // virtual void TearDown() {
+ // }
+
+ // A helper function that some test uses.
+ static int Double(int n) {
+ return 2*n;
+ }
+
+ // A helper function for testing Queue::Map().
+ void MapTester(const Queue<int> * q) {
+ // Creates a new queue, where each element is twice as big as the
+ // corresponding one in q.
+ const Queue<int> * const new_q = q->Map(Double);
+
+ // Verifies that the new queue has the same size as q.
+ ASSERT_EQ(q->Size(), new_q->Size());
+
+ // Verifies the relationship between the elements of the two queues.
+ for ( const QueueNode<int> * n1 = q->Head(), * n2 = new_q->Head();
+ n1 != NULL; n1 = n1->next(), n2 = n2->next() ) {
+ EXPECT_EQ(2 * n1->element(), n2->element());
+ }
+
+ delete new_q;
+ }
+
+ // Declares the variables your tests want to use.
+ Queue<int> q0_;
+ Queue<int> q1_;
+ Queue<int> q2_;
+};
+
+// When you have a test fixture, you define a test using TEST_F
+// instead of TEST.
+
+// Tests the default c'tor.
+TEST_F(QueueTest, DefaultConstructor) {
+ // You can access data in the test fixture here.
+ EXPECT_EQ(0u, q0_.Size());
+}
+
+// Tests Dequeue().
+TEST_F(QueueTest, Dequeue) {
+ int * n = q0_.Dequeue();
+ EXPECT_TRUE(n == NULL);
+
+ n = q1_.Dequeue();
+ ASSERT_TRUE(n != NULL);
+ EXPECT_EQ(1, *n);
+ EXPECT_EQ(0u, q1_.Size());
+ delete n;
+
+ n = q2_.Dequeue();
+ ASSERT_TRUE(n != NULL);
+ EXPECT_EQ(2, *n);
+ EXPECT_EQ(1u, q2_.Size());
+ delete n;
+}
+
+// Tests the Queue::Map() function.
+TEST_F(QueueTest, Map) {
+ MapTester(&q0_);
+ MapTester(&q1_);
+ MapTester(&q2_);
+}
diff --git a/Source/ThirdParty/gtest/samples/sample4.cc b/Source/ThirdParty/gtest/samples/sample4.cc
new file mode 100644
index 000000000..ae44bda6f
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample4.cc
@@ -0,0 +1,46 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <stdio.h>
+
+#include "sample4.h"
+
+// Returns the current counter value, and increments it.
+int Counter::Increment() {
+ return counter_++;
+}
+
+// Prints the current counter value to STDOUT.
+void Counter::Print() const {
+ printf("%d", counter_);
+}
diff --git a/Source/ThirdParty/gtest/samples/sample4.h b/Source/ThirdParty/gtest/samples/sample4.h
new file mode 100644
index 000000000..cd60f0dd2
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample4.h
@@ -0,0 +1,53 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A sample program demonstrating using Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_SAMPLES_SAMPLE4_H_
+#define GTEST_SAMPLES_SAMPLE4_H_
+
+// A simple monotonic counter.
+class Counter {
+ private:
+ int counter_;
+
+ public:
+ // Creates a counter that starts at 0.
+ Counter() : counter_(0) {}
+
+ // Returns the current counter value, and increments it.
+ int Increment();
+
+ // Prints the current counter value to STDOUT.
+ void Print() const;
+};
+
+#endif // GTEST_SAMPLES_SAMPLE4_H_
diff --git a/Source/ThirdParty/gtest/samples/sample4_unittest.cc b/Source/ThirdParty/gtest/samples/sample4_unittest.cc
new file mode 100644
index 000000000..b4fb3736a
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample4_unittest.cc
@@ -0,0 +1,45 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/gtest.h>
+#include "sample4.h"
+
+// Tests the Increment() method.
+TEST(Counter, Increment) {
+ Counter c;
+
+ // EXPECT_EQ() evaluates its arguments exactly once, so they
+ // can have side effects.
+
+ EXPECT_EQ(0, c.Increment());
+ EXPECT_EQ(1, c.Increment());
+ EXPECT_EQ(2, c.Increment());
+}
diff --git a/Source/ThirdParty/gtest/samples/sample5_unittest.cc b/Source/ThirdParty/gtest/samples/sample5_unittest.cc
new file mode 100644
index 000000000..49dae7c69
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample5_unittest.cc
@@ -0,0 +1,199 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// This sample teaches how to reuse a test fixture in multiple test
+// cases by deriving sub-fixtures from it.
+//
+// When you define a test fixture, you specify the name of the test
+// case that will use this fixture. Therefore, a test fixture can
+// be used by only one test case.
+//
+// Sometimes, more than one test cases may want to use the same or
+// slightly different test fixtures. For example, you may want to
+// make sure that all tests for a GUI library don't leak important
+// system resources like fonts and brushes. In Google Test, you do
+// this by putting the shared logic in a super (as in "super class")
+// test fixture, and then have each test case use a fixture derived
+// from this super fixture.
+
+#include <limits.h>
+#include <time.h>
+#include "sample3-inl.h"
+#include <gtest/gtest.h>
+#include "sample1.h"
+
+// In this sample, we want to ensure that every test finishes within
+// ~5 seconds. If a test takes longer to run, we consider it a
+// failure.
+//
+// We put the code for timing a test in a test fixture called
+// "QuickTest". QuickTest is intended to be the super fixture that
+// other fixtures derive from, therefore there is no test case with
+// the name "QuickTest". This is OK.
+//
+// Later, we will derive multiple test fixtures from QuickTest.
+class QuickTest : public testing::Test {
+ protected:
+ // Remember that SetUp() is run immediately before a test starts.
+ // This is a good place to record the start time.
+ virtual void SetUp() {
+ start_time_ = time(NULL);
+ }
+
+ // TearDown() is invoked immediately after a test finishes. Here we
+ // check if the test was too slow.
+ virtual void TearDown() {
+ // Gets the time when the test finishes
+ const time_t end_time = time(NULL);
+
+ // Asserts that the test took no more than ~5 seconds. Did you
+ // know that you can use assertions in SetUp() and TearDown() as
+ // well?
+ EXPECT_TRUE(end_time - start_time_ <= 5) << "The test took too long.";
+ }
+
+ // The UTC time (in seconds) when the test starts
+ time_t start_time_;
+};
+
+
+// We derive a fixture named IntegerFunctionTest from the QuickTest
+// fixture. All tests using this fixture will be automatically
+// required to be quick.
+class IntegerFunctionTest : public QuickTest {
+ // We don't need any more logic than already in the QuickTest fixture.
+ // Therefore the body is empty.
+};
+
+
+// Now we can write tests in the IntegerFunctionTest test case.
+
+// Tests Factorial()
+TEST_F(IntegerFunctionTest, Factorial) {
+ // Tests factorial of negative numbers.
+ EXPECT_EQ(1, Factorial(-5));
+ EXPECT_EQ(1, Factorial(-1));
+ EXPECT_TRUE(Factorial(-10) > 0);
+
+ // Tests factorial of 0.
+ EXPECT_EQ(1, Factorial(0));
+
+ // Tests factorial of positive numbers.
+ EXPECT_EQ(1, Factorial(1));
+ EXPECT_EQ(2, Factorial(2));
+ EXPECT_EQ(6, Factorial(3));
+ EXPECT_EQ(40320, Factorial(8));
+}
+
+
+// Tests IsPrime()
+TEST_F(IntegerFunctionTest, IsPrime) {
+ // Tests negative input.
+ EXPECT_TRUE(!IsPrime(-1));
+ EXPECT_TRUE(!IsPrime(-2));
+ EXPECT_TRUE(!IsPrime(INT_MIN));
+
+ // Tests some trivial cases.
+ EXPECT_TRUE(!IsPrime(0));
+ EXPECT_TRUE(!IsPrime(1));
+ EXPECT_TRUE(IsPrime(2));
+ EXPECT_TRUE(IsPrime(3));
+
+ // Tests positive input.
+ EXPECT_TRUE(!IsPrime(4));
+ EXPECT_TRUE(IsPrime(5));
+ EXPECT_TRUE(!IsPrime(6));
+ EXPECT_TRUE(IsPrime(23));
+}
+
+
+// The next test case (named "QueueTest") also needs to be quick, so
+// we derive another fixture from QuickTest.
+//
+// The QueueTest test fixture has some logic and shared objects in
+// addition to what's in QuickTest already. We define the additional
+// stuff inside the body of the test fixture, as usual.
+class QueueTest : public QuickTest {
+ protected:
+ virtual void SetUp() {
+ // First, we need to set up the super fixture (QuickTest).
+ QuickTest::SetUp();
+
+ // Second, some additional setup for this fixture.
+ q1_.Enqueue(1);
+ q2_.Enqueue(2);
+ q2_.Enqueue(3);
+ }
+
+ // By default, TearDown() inherits the behavior of
+ // QuickTest::TearDown(). As we have no additional cleaning work
+ // for QueueTest, we omit it here.
+ //
+ // virtual void TearDown() {
+ // QuickTest::TearDown();
+ // }
+
+ Queue<int> q0_;
+ Queue<int> q1_;
+ Queue<int> q2_;
+};
+
+
+// Now, let's write tests using the QueueTest fixture.
+
+// Tests the default constructor.
+TEST_F(QueueTest, DefaultConstructor) {
+ EXPECT_EQ(0u, q0_.Size());
+}
+
+// Tests Dequeue().
+TEST_F(QueueTest, Dequeue) {
+ int* n = q0_.Dequeue();
+ EXPECT_TRUE(n == NULL);
+
+ n = q1_.Dequeue();
+ EXPECT_TRUE(n != NULL);
+ EXPECT_EQ(1, *n);
+ EXPECT_EQ(0u, q1_.Size());
+ delete n;
+
+ n = q2_.Dequeue();
+ EXPECT_TRUE(n != NULL);
+ EXPECT_EQ(2, *n);
+ EXPECT_EQ(1u, q2_.Size());
+ delete n;
+}
+
+// If necessary, you can derive further test fixtures from a derived
+// fixture itself. For example, you can derive another fixture from
+// QueueTest. Google Test imposes no limit on how deep the hierarchy
+// can be. In practice, however, you probably don't want it to be too
+// deep as to be confusing.
diff --git a/Source/ThirdParty/gtest/samples/sample6_unittest.cc b/Source/ThirdParty/gtest/samples/sample6_unittest.cc
new file mode 100644
index 000000000..dd0df31f0
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample6_unittest.cc
@@ -0,0 +1,224 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// This sample shows how to test common properties of multiple
+// implementations of the same interface (aka interface tests).
+
+// The interface and its implementations are in this header.
+#include "prime_tables.h"
+
+#include <gtest/gtest.h>
+
+// First, we define some factory functions for creating instances of
+// the implementations. You may be able to skip this step if all your
+// implementations can be constructed the same way.
+
+template <class T>
+PrimeTable* CreatePrimeTable();
+
+template <>
+PrimeTable* CreatePrimeTable<OnTheFlyPrimeTable>() {
+ return new OnTheFlyPrimeTable;
+}
+
+template <>
+PrimeTable* CreatePrimeTable<PreCalculatedPrimeTable>() {
+ return new PreCalculatedPrimeTable(10000);
+}
+
+// Then we define a test fixture class template.
+template <class T>
+class PrimeTableTest : public testing::Test {
+ protected:
+ // The ctor calls the factory function to create a prime table
+ // implemented by T.
+ PrimeTableTest() : table_(CreatePrimeTable<T>()) {}
+
+ virtual ~PrimeTableTest() { delete table_; }
+
+ // Note that we test an implementation via the base interface
+ // instead of the actual implementation class. This is important
+ // for keeping the tests close to the real world scenario, where the
+ // implementation is invoked via the base interface. It avoids
+ // got-yas where the implementation class has a method that shadows
+ // a method with the same name (but slightly different argument
+ // types) in the base interface, for example.
+ PrimeTable* const table_;
+};
+
+#if GTEST_HAS_TYPED_TEST
+
+using testing::Types;
+
+// Google Test offers two ways for reusing tests for different types.
+// The first is called "typed tests". You should use it if you
+// already know *all* the types you are gonna exercise when you write
+// the tests.
+
+// To write a typed test case, first use
+//
+// TYPED_TEST_CASE(TestCaseName, TypeList);
+//
+// to declare it and specify the type parameters. As with TEST_F,
+// TestCaseName must match the test fixture name.
+
+// The list of types we want to test.
+typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> Implementations;
+
+TYPED_TEST_CASE(PrimeTableTest, Implementations);
+
+// Then use TYPED_TEST(TestCaseName, TestName) to define a typed test,
+// similar to TEST_F.
+TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes) {
+ // Inside the test body, you can refer to the type parameter by
+ // TypeParam, and refer to the fixture class by TestFixture. We
+ // don't need them in this example.
+
+ // Since we are in the template world, C++ requires explicitly
+ // writing 'this->' when referring to members of the fixture class.
+ // This is something you have to learn to live with.
+ EXPECT_FALSE(this->table_->IsPrime(-5));
+ EXPECT_FALSE(this->table_->IsPrime(0));
+ EXPECT_FALSE(this->table_->IsPrime(1));
+ EXPECT_FALSE(this->table_->IsPrime(4));
+ EXPECT_FALSE(this->table_->IsPrime(6));
+ EXPECT_FALSE(this->table_->IsPrime(100));
+}
+
+TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes) {
+ EXPECT_TRUE(this->table_->IsPrime(2));
+ EXPECT_TRUE(this->table_->IsPrime(3));
+ EXPECT_TRUE(this->table_->IsPrime(5));
+ EXPECT_TRUE(this->table_->IsPrime(7));
+ EXPECT_TRUE(this->table_->IsPrime(11));
+ EXPECT_TRUE(this->table_->IsPrime(131));
+}
+
+TYPED_TEST(PrimeTableTest, CanGetNextPrime) {
+ EXPECT_EQ(2, this->table_->GetNextPrime(0));
+ EXPECT_EQ(3, this->table_->GetNextPrime(2));
+ EXPECT_EQ(5, this->table_->GetNextPrime(3));
+ EXPECT_EQ(7, this->table_->GetNextPrime(5));
+ EXPECT_EQ(11, this->table_->GetNextPrime(7));
+ EXPECT_EQ(131, this->table_->GetNextPrime(128));
+}
+
+// That's it! Google Test will repeat each TYPED_TEST for each type
+// in the type list specified in TYPED_TEST_CASE. Sit back and be
+// happy that you don't have to define them multiple times.
+
+#endif // GTEST_HAS_TYPED_TEST
+
+#if GTEST_HAS_TYPED_TEST_P
+
+using testing::Types;
+
+// Sometimes, however, you don't yet know all the types that you want
+// to test when you write the tests. For example, if you are the
+// author of an interface and expect other people to implement it, you
+// might want to write a set of tests to make sure each implementation
+// conforms to some basic requirements, but you don't know what
+// implementations will be written in the future.
+//
+// How can you write the tests without committing to the type
+// parameters? That's what "type-parameterized tests" can do for you.
+// It is a bit more involved than typed tests, but in return you get a
+// test pattern that can be reused in many contexts, which is a big
+// win. Here's how you do it:
+
+// First, define a test fixture class template. Here we just reuse
+// the PrimeTableTest fixture defined earlier:
+
+template <class T>
+class PrimeTableTest2 : public PrimeTableTest<T> {
+};
+
+// Then, declare the test case. The argument is the name of the test
+// fixture, and also the name of the test case (as usual). The _P
+// suffix is for "parameterized" or "pattern".
+TYPED_TEST_CASE_P(PrimeTableTest2);
+
+// Next, use TYPED_TEST_P(TestCaseName, TestName) to define a test,
+// similar to what you do with TEST_F.
+TYPED_TEST_P(PrimeTableTest2, ReturnsFalseForNonPrimes) {
+ EXPECT_FALSE(this->table_->IsPrime(-5));
+ EXPECT_FALSE(this->table_->IsPrime(0));
+ EXPECT_FALSE(this->table_->IsPrime(1));
+ EXPECT_FALSE(this->table_->IsPrime(4));
+ EXPECT_FALSE(this->table_->IsPrime(6));
+ EXPECT_FALSE(this->table_->IsPrime(100));
+}
+
+TYPED_TEST_P(PrimeTableTest2, ReturnsTrueForPrimes) {
+ EXPECT_TRUE(this->table_->IsPrime(2));
+ EXPECT_TRUE(this->table_->IsPrime(3));
+ EXPECT_TRUE(this->table_->IsPrime(5));
+ EXPECT_TRUE(this->table_->IsPrime(7));
+ EXPECT_TRUE(this->table_->IsPrime(11));
+ EXPECT_TRUE(this->table_->IsPrime(131));
+}
+
+TYPED_TEST_P(PrimeTableTest2, CanGetNextPrime) {
+ EXPECT_EQ(2, this->table_->GetNextPrime(0));
+ EXPECT_EQ(3, this->table_->GetNextPrime(2));
+ EXPECT_EQ(5, this->table_->GetNextPrime(3));
+ EXPECT_EQ(7, this->table_->GetNextPrime(5));
+ EXPECT_EQ(11, this->table_->GetNextPrime(7));
+ EXPECT_EQ(131, this->table_->GetNextPrime(128));
+}
+
+// Type-parameterized tests involve one extra step: you have to
+// enumerate the tests you defined:
+REGISTER_TYPED_TEST_CASE_P(
+ PrimeTableTest2, // The first argument is the test case name.
+ // The rest of the arguments are the test names.
+ ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime);
+
+// At this point the test pattern is done. However, you don't have
+// any real test yet as you haven't said which types you want to run
+// the tests with.
+
+// To turn the abstract test pattern into real tests, you instantiate
+// it with a list of types. Usually the test pattern will be defined
+// in a .h file, and anyone can #include and instantiate it. You can
+// even instantiate it more than once in the same program. To tell
+// different instances apart, you give each of them a name, which will
+// become part of the test case name and can be used in test filters.
+
+// The list of types we want to test. Note that it doesn't have to be
+// defined at the time we write the TYPED_TEST_P()s.
+typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable>
+ PrimeTableImplementations;
+INSTANTIATE_TYPED_TEST_CASE_P(OnTheFlyAndPreCalculated, // Instance name
+ PrimeTableTest2, // Test case name
+ PrimeTableImplementations); // Type list
+
+#endif // GTEST_HAS_TYPED_TEST_P
diff --git a/Source/ThirdParty/gtest/samples/sample7_unittest.cc b/Source/ThirdParty/gtest/samples/sample7_unittest.cc
new file mode 100644
index 000000000..f4552827e
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample7_unittest.cc
@@ -0,0 +1,132 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// This sample shows how to test common properties of multiple
+// implementations of an interface (aka interface tests) using
+// value-parameterized tests. Each test in the test case has
+// a parameter that is an interface pointer to an implementation
+// tested.
+
+// The interface and its implementations are in this header.
+#include "prime_tables.h"
+
+#include <gtest/gtest.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+// As a general rule, tested objects should not be reused between tests.
+// Also, their constructors and destructors of tested objects can have
+// side effects. Thus you should create and destroy them for each test.
+// In this sample we will define a simple factory function for PrimeTable
+// objects. We will instantiate objects in test's SetUp() method and
+// delete them in TearDown() method.
+typedef PrimeTable* CreatePrimeTableFunc();
+
+PrimeTable* CreateOnTheFlyPrimeTable() {
+ return new OnTheFlyPrimeTable();
+}
+
+template <size_t max_precalculated>
+PrimeTable* CreatePreCalculatedPrimeTable() {
+ return new PreCalculatedPrimeTable(max_precalculated);
+}
+
+// Inside the test body, fixture constructor, SetUp(), and TearDown()
+// you can refer to the test parameter by GetParam().
+// In this case, the test parameter is a PrimeTableFactory interface pointer
+// which we use in fixture's SetUp() to create and store an instance of
+// PrimeTable.
+class PrimeTableTest : public TestWithParam<CreatePrimeTableFunc*> {
+ public:
+ virtual ~PrimeTableTest() { delete table_; }
+ virtual void SetUp() { table_ = (*GetParam())(); }
+ virtual void TearDown() {
+ delete table_;
+ table_ = NULL;
+ }
+
+ protected:
+ PrimeTable* table_;
+};
+
+TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) {
+ EXPECT_FALSE(table_->IsPrime(-5));
+ EXPECT_FALSE(table_->IsPrime(0));
+ EXPECT_FALSE(table_->IsPrime(1));
+ EXPECT_FALSE(table_->IsPrime(4));
+ EXPECT_FALSE(table_->IsPrime(6));
+ EXPECT_FALSE(table_->IsPrime(100));
+}
+
+TEST_P(PrimeTableTest, ReturnsTrueForPrimes) {
+ EXPECT_TRUE(table_->IsPrime(2));
+ EXPECT_TRUE(table_->IsPrime(3));
+ EXPECT_TRUE(table_->IsPrime(5));
+ EXPECT_TRUE(table_->IsPrime(7));
+ EXPECT_TRUE(table_->IsPrime(11));
+ EXPECT_TRUE(table_->IsPrime(131));
+}
+
+TEST_P(PrimeTableTest, CanGetNextPrime) {
+ EXPECT_EQ(2, table_->GetNextPrime(0));
+ EXPECT_EQ(3, table_->GetNextPrime(2));
+ EXPECT_EQ(5, table_->GetNextPrime(3));
+ EXPECT_EQ(7, table_->GetNextPrime(5));
+ EXPECT_EQ(11, table_->GetNextPrime(7));
+ EXPECT_EQ(131, table_->GetNextPrime(128));
+}
+
+// In order to run value-parameterized tests, you need to instantiate them,
+// or bind them to a list of values which will be used as test parameters.
+// You can instantiate them in a different translation module, or even
+// instantiate them several times.
+//
+// Here, we instantiate our tests with a list of two PrimeTable object
+// factory functions:
+INSTANTIATE_TEST_CASE_P(
+ OnTheFlyAndPreCalculated,
+ PrimeTableTest,
+ Values(&CreateOnTheFlyPrimeTable, &CreatePreCalculatedPrimeTable<1000>));
+
+#else
+
+// Google Test may not support value-parameterized tests with some
+// compilers. If we use conditional compilation to compile out all
+// code referring to the gtest_main library, MSVC linker will not link
+// that library at all and consequently complain about missing entry
+// point defined in that library (fatal error LNK1561: entry point
+// must be defined). This dummy test keeps gtest_main linked in.
+TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
+
+#endif // GTEST_HAS_PARAM_TEST
diff --git a/Source/ThirdParty/gtest/samples/sample8_unittest.cc b/Source/ThirdParty/gtest/samples/sample8_unittest.cc
new file mode 100644
index 000000000..ccf61d92b
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample8_unittest.cc
@@ -0,0 +1,173 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// This sample shows how to test code relying on some global flag variables.
+// Combine() helps with generating all possible combinations of such flags,
+// and each test is given one combination as a parameter.
+
+// Use class definitions to test from this header.
+#include "prime_tables.h"
+
+#include <gtest/gtest.h>
+
+#if GTEST_HAS_COMBINE
+
+// Suppose we want to introduce a new, improved implementation of PrimeTable
+// which combines speed of PrecalcPrimeTable and versatility of
+// OnTheFlyPrimeTable (see prime_tables.h). Inside it instantiates both
+// PrecalcPrimeTable and OnTheFlyPrimeTable and uses the one that is more
+// appropriate under the circumstances. But in low memory conditions, it can be
+// told to instantiate without PrecalcPrimeTable instance at all and use only
+// OnTheFlyPrimeTable.
+class HybridPrimeTable : public PrimeTable {
+ public:
+ HybridPrimeTable(bool force_on_the_fly, int max_precalculated)
+ : on_the_fly_impl_(new OnTheFlyPrimeTable),
+ precalc_impl_(force_on_the_fly ? NULL :
+ new PreCalculatedPrimeTable(max_precalculated)),
+ max_precalculated_(max_precalculated) {}
+ virtual ~HybridPrimeTable() {
+ delete on_the_fly_impl_;
+ delete precalc_impl_;
+ }
+
+ virtual bool IsPrime(int n) const {
+ if (precalc_impl_ != NULL && n < max_precalculated_)
+ return precalc_impl_->IsPrime(n);
+ else
+ return on_the_fly_impl_->IsPrime(n);
+ }
+
+ virtual int GetNextPrime(int p) const {
+ int next_prime = -1;
+ if (precalc_impl_ != NULL && p < max_precalculated_)
+ next_prime = precalc_impl_->GetNextPrime(p);
+
+ return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p);
+ }
+
+ private:
+ OnTheFlyPrimeTable* on_the_fly_impl_;
+ PreCalculatedPrimeTable* precalc_impl_;
+ int max_precalculated_;
+};
+
+using ::testing::TestWithParam;
+using ::testing::Bool;
+using ::testing::Values;
+using ::testing::Combine;
+
+// To test all code paths for HybridPrimeTable we must test it with numbers
+// both within and outside PreCalculatedPrimeTable's capacity and also with
+// PreCalculatedPrimeTable disabled. We do this by defining fixture which will
+// accept different combinations of parameters for instantiating a
+// HybridPrimeTable instance.
+class PrimeTableTest : public TestWithParam< ::std::tr1::tuple<bool, int> > {
+ protected:
+ virtual void SetUp() {
+ // This can be written as
+ //
+ // bool force_on_the_fly;
+ // int max_precalculated;
+ // tie(force_on_the_fly, max_precalculated) = GetParam();
+ //
+ // once the Google C++ Style Guide allows use of ::std::tr1::tie.
+ //
+ bool force_on_the_fly = ::std::tr1::get<0>(GetParam());
+ int max_precalculated = ::std::tr1::get<1>(GetParam());
+ table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated);
+ }
+ virtual void TearDown() {
+ delete table_;
+ table_ = NULL;
+ }
+ HybridPrimeTable* table_;
+};
+
+TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) {
+ // Inside the test body, you can refer to the test parameter by GetParam().
+ // In this case, the test parameter is a PrimeTable interface pointer which
+ // we can use directly.
+ // Please note that you can also save it in the fixture's SetUp() method
+ // or constructor and use saved copy in the tests.
+
+ EXPECT_FALSE(table_->IsPrime(-5));
+ EXPECT_FALSE(table_->IsPrime(0));
+ EXPECT_FALSE(table_->IsPrime(1));
+ EXPECT_FALSE(table_->IsPrime(4));
+ EXPECT_FALSE(table_->IsPrime(6));
+ EXPECT_FALSE(table_->IsPrime(100));
+}
+
+TEST_P(PrimeTableTest, ReturnsTrueForPrimes) {
+ EXPECT_TRUE(table_->IsPrime(2));
+ EXPECT_TRUE(table_->IsPrime(3));
+ EXPECT_TRUE(table_->IsPrime(5));
+ EXPECT_TRUE(table_->IsPrime(7));
+ EXPECT_TRUE(table_->IsPrime(11));
+ EXPECT_TRUE(table_->IsPrime(131));
+}
+
+TEST_P(PrimeTableTest, CanGetNextPrime) {
+ EXPECT_EQ(2, table_->GetNextPrime(0));
+ EXPECT_EQ(3, table_->GetNextPrime(2));
+ EXPECT_EQ(5, table_->GetNextPrime(3));
+ EXPECT_EQ(7, table_->GetNextPrime(5));
+ EXPECT_EQ(11, table_->GetNextPrime(7));
+ EXPECT_EQ(131, table_->GetNextPrime(128));
+}
+
+// In order to run value-parameterized tests, you need to instantiate them,
+// or bind them to a list of values which will be used as test parameters.
+// You can instantiate them in a different translation module, or even
+// instantiate them several times.
+//
+// Here, we instantiate our tests with a list of parameters. We must combine
+// all variations of the boolean flag suppressing PrecalcPrimeTable and some
+// meaningful values for tests. We choose a small value (1), and a value that
+// will put some of the tested numbers beyond the capability of the
+// PrecalcPrimeTable instance and some inside it (10). Combine will produce all
+// possible combinations.
+INSTANTIATE_TEST_CASE_P(MeaningfulTestParameters,
+ PrimeTableTest,
+ Combine(Bool(), Values(1, 10)));
+
+#else
+
+// Google Test may not support Combine() with some compilers. If we
+// use conditional compilation to compile out all code referring to
+// the gtest_main library, MSVC linker will not link that library at
+// all and consequently complain about missing entry point defined in
+// that library (fatal error LNK1561: entry point must be
+// defined). This dummy test keeps gtest_main linked in.
+TEST(DummyTest, CombineIsNotSupportedOnThisPlatform) {}
+
+#endif // GTEST_HAS_COMBINE
diff --git a/Source/ThirdParty/gtest/samples/sample9_unittest.cc b/Source/ThirdParty/gtest/samples/sample9_unittest.cc
new file mode 100644
index 000000000..d828ef4d8
--- /dev/null
+++ b/Source/ThirdParty/gtest/samples/sample9_unittest.cc
@@ -0,0 +1,160 @@
+// Copyright 2009 Google Inc. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+
+// This sample shows how to use Google Test listener API to implement
+// an alternative console output and how to use the UnitTest reflection API
+// to enumerate test cases and tests and to inspect their results.
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+
+using ::testing::EmptyTestEventListener;
+using ::testing::InitGoogleTest;
+using ::testing::Test;
+using ::testing::TestCase;
+using ::testing::TestEventListeners;
+using ::testing::TestInfo;
+using ::testing::TestPartResult;
+using ::testing::UnitTest;
+
+namespace {
+
+// Provides alternative output mode which produces minimal amount of
+// information about tests.
+class TersePrinter : public EmptyTestEventListener {
+ private:
+ // Called before any test activity starts.
+ virtual void OnTestProgramStart(const UnitTest& /* unit_test */) {}
+
+ // Called after all test activities have ended.
+ virtual void OnTestProgramEnd(const UnitTest& unit_test) {
+ fprintf(stdout, "TEST %s\n", unit_test.Passed() ? "PASSED" : "FAILED");
+ fflush(stdout);
+ }
+
+ // Called before a test starts.
+ virtual void OnTestStart(const TestInfo& test_info) {
+ fprintf(stdout,
+ "*** Test %s.%s starting.\n",
+ test_info.test_case_name(),
+ test_info.name());
+ fflush(stdout);
+ }
+
+ // Called after a failed assertion or a SUCCESS().
+ virtual void OnTestPartResult(const TestPartResult& test_part_result) {
+ fprintf(stdout,
+ "%s in %s:%d\n%s\n",
+ test_part_result.failed() ? "*** Failure" : "Success",
+ test_part_result.file_name(),
+ test_part_result.line_number(),
+ test_part_result.summary());
+ fflush(stdout);
+ }
+
+ // Called after a test ends.
+ virtual void OnTestEnd(const TestInfo& test_info) {
+ fprintf(stdout,
+ "*** Test %s.%s ending.\n",
+ test_info.test_case_name(),
+ test_info.name());
+ fflush(stdout);
+ }
+}; // class TersePrinter
+
+TEST(CustomOutputTest, PrintsMessage) {
+ printf("Printing something from the test body...\n");
+}
+
+TEST(CustomOutputTest, Succeeds) {
+ SUCCEED() << "SUCCEED() has been invoked from here";
+}
+
+TEST(CustomOutputTest, Fails) {
+ EXPECT_EQ(1, 2)
+ << "This test fails in order to demonstrate alternative failure messages";
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ InitGoogleTest(&argc, argv);
+
+ bool terse_output = false;
+ if (argc > 1 && strcmp(argv[1], "--terse_output") == 0 )
+ terse_output = true;
+ else
+ printf("%s\n", "Run this program with --terse_output to change the way "
+ "it prints its output.");
+
+ UnitTest& unit_test = *UnitTest::GetInstance();
+
+ // If we are given the --terse_output command line flag, suppresses the
+ // standard output and attaches own result printer.
+ if (terse_output) {
+ TestEventListeners& listeners = unit_test.listeners();
+
+ // Removes the default console output listener from the list so it will
+ // not receive events from Google Test and won't print any output. Since
+ // this operation transfers ownership of the listener to the caller we
+ // have to delete it as well.
+ delete listeners.Release(listeners.default_result_printer());
+
+ // Adds the custom output listener to the list. It will now receive
+ // events from Google Test and print the alternative output. We don't
+ // have to worry about deleting it since Google Test assumes ownership
+ // over it after adding it to the list.
+ listeners.Append(new TersePrinter);
+ }
+ int ret_val = RUN_ALL_TESTS();
+
+ // This is an example of using the UnitTest reflection API to inspect test
+ // results. Here we discount failures from the tests we expected to fail.
+ int unexpectedly_failed_tests = 0;
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ const TestCase& test_case = *unit_test.GetTestCase(i);
+ for (int j = 0; j < test_case.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_case.GetTestInfo(j);
+ // Counts failed tests that were not meant to fail (those without
+ // 'Fails' in the name).
+ if (test_info.result()->Failed() &&
+ strcmp(test_info.name(), "Fails") != 0) {
+ unexpectedly_failed_tests++;
+ }
+ }
+ }
+
+ // Test that were meant to fail should not affect the test program outcome.
+ if (unexpectedly_failed_tests == 0)
+ ret_val = 0;
+
+ return ret_val;
+}
diff --git a/Source/ThirdParty/gtest/scripts/fuse_gtest_files.py b/Source/ThirdParty/gtest/scripts/fuse_gtest_files.py
new file mode 100755
index 000000000..148444ca7
--- /dev/null
+++ b/Source/ThirdParty/gtest/scripts/fuse_gtest_files.py
@@ -0,0 +1,250 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""fuse_gtest_files.py v0.2.0
+Fuses Google Test source code into a .h file and a .cc file.
+
+SYNOPSIS
+ fuse_gtest_files.py [GTEST_ROOT_DIR] OUTPUT_DIR
+
+ Scans GTEST_ROOT_DIR for Google Test source code, and generates
+ two files: OUTPUT_DIR/gtest/gtest.h and OUTPUT_DIR/gtest/gtest-all.cc.
+ Then you can build your tests by adding OUTPUT_DIR to the include
+ search path and linking with OUTPUT_DIR/gtest/gtest-all.cc. These
+ two files contain everything you need to use Google Test. Hence
+ you can "install" Google Test by copying them to wherever you want.
+
+ GTEST_ROOT_DIR can be omitted and defaults to the parent
+ directory of the directory holding this script.
+
+EXAMPLES
+ ./fuse_gtest_files.py fused_gtest
+ ./fuse_gtest_files.py path/to/unpacked/gtest fused_gtest
+
+This tool is experimental. In particular, it assumes that there is no
+conditional inclusion of Google Test headers. Please report any
+problems to googletestframework@googlegroups.com. You can read
+http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide for
+more information.
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import re
+import sets
+import sys
+
+# We assume that this file is in the scripts/ directory in the Google
+# Test root directory.
+DEFAULT_GTEST_ROOT_DIR = os.path.join(os.path.dirname(__file__), '..')
+
+# Regex for matching '#include <gtest/...>'.
+INCLUDE_GTEST_FILE_REGEX = re.compile(r'^\s*#\s*include\s*<(gtest/.+)>')
+
+# Regex for matching '#include "src/..."'.
+INCLUDE_SRC_FILE_REGEX = re.compile(r'^\s*#\s*include\s*"(src/.+)"')
+
+# Where to find the source seed files.
+GTEST_H_SEED = 'include/gtest/gtest.h'
+GTEST_SPI_H_SEED = 'include/gtest/gtest-spi.h'
+GTEST_ALL_CC_SEED = 'src/gtest-all.cc'
+
+# Where to put the generated files.
+GTEST_H_OUTPUT = 'gtest/gtest.h'
+GTEST_ALL_CC_OUTPUT = 'gtest/gtest-all.cc'
+
+
+def VerifyFileExists(directory, relative_path):
+ """Verifies that the given file exists; aborts on failure.
+
+ relative_path is the file path relative to the given directory.
+ """
+
+ if not os.path.isfile(os.path.join(directory, relative_path)):
+ print 'ERROR: Cannot find %s in directory %s.' % (relative_path,
+ directory)
+ print ('Please either specify a valid project root directory '
+ 'or omit it on the command line.')
+ sys.exit(1)
+
+
+def ValidateGTestRootDir(gtest_root):
+ """Makes sure gtest_root points to a valid gtest root directory.
+
+ The function aborts the program on failure.
+ """
+
+ VerifyFileExists(gtest_root, GTEST_H_SEED)
+ VerifyFileExists(gtest_root, GTEST_ALL_CC_SEED)
+
+
+def VerifyOutputFile(output_dir, relative_path):
+ """Verifies that the given output file path is valid.
+
+ relative_path is relative to the output_dir directory.
+ """
+
+ # Makes sure the output file either doesn't exist or can be overwritten.
+ output_file = os.path.join(output_dir, relative_path)
+ if os.path.exists(output_file):
+ # TODO(wan@google.com): The following user-interaction doesn't
+ # work with automated processes. We should provide a way for the
+ # Makefile to force overwriting the files.
+ print ('%s already exists in directory %s - overwrite it? (y/N) ' %
+ (relative_path, output_dir))
+ answer = sys.stdin.readline().strip()
+ if answer not in ['y', 'Y']:
+ print 'ABORTED.'
+ sys.exit(1)
+
+ # Makes sure the directory holding the output file exists; creates
+ # it and all its ancestors if necessary.
+ parent_directory = os.path.dirname(output_file)
+ if not os.path.isdir(parent_directory):
+ os.makedirs(parent_directory)
+
+
+def ValidateOutputDir(output_dir):
+ """Makes sure output_dir points to a valid output directory.
+
+ The function aborts the program on failure.
+ """
+
+ VerifyOutputFile(output_dir, GTEST_H_OUTPUT)
+ VerifyOutputFile(output_dir, GTEST_ALL_CC_OUTPUT)
+
+
+def FuseGTestH(gtest_root, output_dir):
+ """Scans folder gtest_root to generate gtest/gtest.h in output_dir."""
+
+ output_file = file(os.path.join(output_dir, GTEST_H_OUTPUT), 'w')
+ processed_files = sets.Set() # Holds all gtest headers we've processed.
+
+ def ProcessFile(gtest_header_path):
+ """Processes the given gtest header file."""
+
+ # We don't process the same header twice.
+ if gtest_header_path in processed_files:
+ return
+
+ processed_files.add(gtest_header_path)
+
+ # Reads each line in the given gtest header.
+ for line in file(os.path.join(gtest_root, gtest_header_path), 'r'):
+ m = INCLUDE_GTEST_FILE_REGEX.match(line)
+ if m:
+ # It's '#include <gtest/...>' - let's process it recursively.
+ ProcessFile('include/' + m.group(1))
+ else:
+ # Otherwise we copy the line unchanged to the output file.
+ output_file.write(line)
+
+ ProcessFile(GTEST_H_SEED)
+ output_file.close()
+
+
+def FuseGTestAllCcToFile(gtest_root, output_file):
+ """Scans folder gtest_root to generate gtest/gtest-all.cc in output_file."""
+
+ processed_files = sets.Set()
+
+ def ProcessFile(gtest_source_file):
+ """Processes the given gtest source file."""
+
+ # We don't process the same #included file twice.
+ if gtest_source_file in processed_files:
+ return
+
+ processed_files.add(gtest_source_file)
+
+ # Reads each line in the given gtest source file.
+ for line in file(os.path.join(gtest_root, gtest_source_file), 'r'):
+ m = INCLUDE_GTEST_FILE_REGEX.match(line)
+ if m:
+ if 'include/' + m.group(1) == GTEST_SPI_H_SEED:
+ # It's '#include <gtest/gtest-spi.h>'. This file is not
+ # #included by <gtest/gtest.h>, so we need to process it.
+ ProcessFile(GTEST_SPI_H_SEED)
+ else:
+ # It's '#include <gtest/foo.h>' where foo is not gtest-spi.
+ # We treat it as '#include <gtest/gtest.h>', as all other
+ # gtest headers are being fused into gtest.h and cannot be
+ # #included directly.
+
+ # There is no need to #include <gtest/gtest.h> more than once.
+ if not GTEST_H_SEED in processed_files:
+ processed_files.add(GTEST_H_SEED)
+ output_file.write('#include <%s>\n' % (GTEST_H_OUTPUT,))
+ else:
+ m = INCLUDE_SRC_FILE_REGEX.match(line)
+ if m:
+ # It's '#include "src/foo"' - let's process it recursively.
+ ProcessFile(m.group(1))
+ else:
+ output_file.write(line)
+
+ ProcessFile(GTEST_ALL_CC_SEED)
+
+
+def FuseGTestAllCc(gtest_root, output_dir):
+ """Scans folder gtest_root to generate gtest/gtest-all.cc in output_dir."""
+
+ output_file = file(os.path.join(output_dir, GTEST_ALL_CC_OUTPUT), 'w')
+ FuseGTestAllCcToFile(gtest_root, output_file)
+ output_file.close()
+
+
+def FuseGTest(gtest_root, output_dir):
+ """Fuses gtest.h and gtest-all.cc."""
+
+ ValidateGTestRootDir(gtest_root)
+ ValidateOutputDir(output_dir)
+
+ FuseGTestH(gtest_root, output_dir)
+ FuseGTestAllCc(gtest_root, output_dir)
+
+
+def main():
+ argc = len(sys.argv)
+ if argc == 2:
+ # fuse_gtest_files.py OUTPUT_DIR
+ FuseGTest(DEFAULT_GTEST_ROOT_DIR, sys.argv[1])
+ elif argc == 3:
+ # fuse_gtest_files.py GTEST_ROOT_DIR OUTPUT_DIR
+ FuseGTest(sys.argv[1], sys.argv[2])
+ else:
+ print __doc__
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/Source/ThirdParty/gtest/scripts/gen_gtest_pred_impl.py b/Source/ThirdParty/gtest/scripts/gen_gtest_pred_impl.py
new file mode 100755
index 000000000..8307134ad
--- /dev/null
+++ b/Source/ThirdParty/gtest/scripts/gen_gtest_pred_impl.py
@@ -0,0 +1,733 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""gen_gtest_pred_impl.py v0.1
+
+Generates the implementation of Google Test predicate assertions and
+accompanying tests.
+
+Usage:
+
+ gen_gtest_pred_impl.py MAX_ARITY
+
+where MAX_ARITY is a positive integer.
+
+The command generates the implementation of up-to MAX_ARITY-ary
+predicate assertions, and writes it to file gtest_pred_impl.h in the
+directory where the script is. It also generates the accompanying
+unit test in file gtest_pred_impl_unittest.cc.
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import sys
+import time
+
+# Where this script is.
+SCRIPT_DIR = os.path.dirname(sys.argv[0])
+
+# Where to store the generated header.
+HEADER = os.path.join(SCRIPT_DIR, '../include/gtest/gtest_pred_impl.h')
+
+# Where to store the generated unit test.
+UNIT_TEST = os.path.join(SCRIPT_DIR, '../test/gtest_pred_impl_unittest.cc')
+
+
+def HeaderPreamble(n):
+ """Returns the preamble for the header file.
+
+ Args:
+ n: the maximum arity of the predicate macros to be generated.
+ """
+
+ # A map that defines the values used in the preamble template.
+ DEFS = {
+ 'today' : time.strftime('%m/%d/%Y'),
+ 'year' : time.strftime('%Y'),
+ 'command' : '%s %s' % (os.path.basename(sys.argv[0]), n),
+ 'n' : n
+ }
+
+ return (
+"""// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on %(today)s by command
+// '%(command)s'. DO NOT EDIT BY HAND!
+//
+// Implements a family of generic predicate assertion macros.
+
+#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+
+// Makes sure this header is not included before gtest.h.
+#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
+#error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
+#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+
+// This header implements a family of generic predicate assertion
+// macros:
+//
+// ASSERT_PRED_FORMAT1(pred_format, v1)
+// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
+// ...
+//
+// where pred_format is a function or functor that takes n (in the
+// case of ASSERT_PRED_FORMATn) values and their source expression
+// text, and returns a testing::AssertionResult. See the definition
+// of ASSERT_EQ in gtest.h for an example.
+//
+// If you don't care about formatting, you can use the more
+// restrictive version:
+//
+// ASSERT_PRED1(pred, v1)
+// ASSERT_PRED2(pred, v1, v2)
+// ...
+//
+// where pred is an n-ary function or functor that returns bool,
+// and the values v1, v2, ..., must support the << operator for
+// streaming to std::ostream.
+//
+// We also define the EXPECT_* variations.
+//
+// For now we only support predicates whose arity is at most %(n)s.
+// Please email googletestframework@googlegroups.com if you need
+// support for higher arities.
+
+// GTEST_ASSERT_ is the basic statement to which all of the assertions
+// in this file reduce. Don't use this in your code.
+
+#define GTEST_ASSERT_(expression, on_failure) \\
+ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \\
+ if (const ::testing::AssertionResult gtest_ar = (expression)) \\
+ ; \\
+ else \\
+ on_failure(gtest_ar.failure_message())
+""" % DEFS)
+
+
+def Arity(n):
+ """Returns the English name of the given arity."""
+
+ if n < 0:
+ return None
+ elif n <= 3:
+ return ['nullary', 'unary', 'binary', 'ternary'][n]
+ else:
+ return '%s-ary' % n
+
+
+def Title(word):
+ """Returns the given word in title case. The difference between
+ this and string's title() method is that Title('4-ary') is '4-ary'
+ while '4-ary'.title() is '4-Ary'."""
+
+ return word[0].upper() + word[1:]
+
+
+def OneTo(n):
+ """Returns the list [1, 2, 3, ..., n]."""
+
+ return range(1, n + 1)
+
+
+def Iter(n, format, sep=''):
+ """Given a positive integer n, a format string that contains 0 or
+ more '%s' format specs, and optionally a separator string, returns
+ the join of n strings, each formatted with the format string on an
+ iterator ranged from 1 to n.
+
+ Example:
+
+ Iter(3, 'v%s', sep=', ') returns 'v1, v2, v3'.
+ """
+
+ # How many '%s' specs are in format?
+ spec_count = len(format.split('%s')) - 1
+ return sep.join([format % (spec_count * (i,)) for i in OneTo(n)])
+
+
+def ImplementationForArity(n):
+ """Returns the implementation of n-ary predicate assertions."""
+
+ # A map the defines the values used in the implementation template.
+ DEFS = {
+ 'n' : str(n),
+ 'vs' : Iter(n, 'v%s', sep=', '),
+ 'vts' : Iter(n, '#v%s', sep=', '),
+ 'arity' : Arity(n),
+ 'Arity' : Title(Arity(n))
+ }
+
+ impl = """
+
+// Helper function for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use
+// this in your code.
+template <typename Pred""" % DEFS
+
+ impl += Iter(n, """,
+ typename T%s""")
+
+ impl += """>
+AssertionResult AssertPred%(n)sHelper(const char* pred_text""" % DEFS
+
+ impl += Iter(n, """,
+ const char* e%s""")
+
+ impl += """,
+ Pred pred"""
+
+ impl += Iter(n, """,
+ const T%s& v%s""")
+
+ impl += """) {
+ if (pred(%(vs)s)) return AssertionSuccess();
+
+ Message msg;
+""" % DEFS
+
+ impl += ' msg << pred_text << "("'
+
+ impl += Iter(n, """
+ << e%s""", sep=' << ", "')
+
+ impl += ' << ") evaluates to false, where"'
+
+ impl += Iter(n, """
+ << "\\n" << e%s << " evaluates to " << v%s""")
+
+ impl += """;
+ return AssertionFailure(msg);
+}
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT%(n)s.
+// Don't use this in your code.
+#define GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, on_failure)\\
+ GTEST_ASSERT_(pred_format(%(vts)s, %(vs)s),\\
+ on_failure)
+
+// Internal macro for implementing {EXPECT|ASSERT}_PRED%(n)s. Don't use
+// this in your code.
+#define GTEST_PRED%(n)s_(pred, %(vs)s, on_failure)\\
+ GTEST_ASSERT_(::testing::AssertPred%(n)sHelper(#pred""" % DEFS
+
+ impl += Iter(n, """, \\
+ #v%s""")
+
+ impl += """, \\
+ pred"""
+
+ impl += Iter(n, """, \\
+ v%s""")
+
+ impl += """), on_failure)
+
+// %(Arity)s predicate assertion macros.
+#define EXPECT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\
+ GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_NONFATAL_FAILURE_)
+#define EXPECT_PRED%(n)s(pred, %(vs)s) \\
+ GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_NONFATAL_FAILURE_)
+#define ASSERT_PRED_FORMAT%(n)s(pred_format, %(vs)s) \\
+ GTEST_PRED_FORMAT%(n)s_(pred_format, %(vs)s, GTEST_FATAL_FAILURE_)
+#define ASSERT_PRED%(n)s(pred, %(vs)s) \\
+ GTEST_PRED%(n)s_(pred, %(vs)s, GTEST_FATAL_FAILURE_)
+
+""" % DEFS
+
+ return impl
+
+
+def HeaderPostamble():
+ """Returns the postamble for the header file."""
+
+ return """
+
+#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
+"""
+
+
+def GenerateFile(path, content):
+ """Given a file path and a content string, overwrites it with the
+ given content."""
+
+ print 'Updating file %s . . .' % path
+
+ f = file(path, 'w+')
+ print >>f, content,
+ f.close()
+
+ print 'File %s has been updated.' % path
+
+
+def GenerateHeader(n):
+ """Given the maximum arity n, updates the header file that implements
+ the predicate assertions."""
+
+ GenerateFile(HEADER,
+ HeaderPreamble(n)
+ + ''.join([ImplementationForArity(i) for i in OneTo(n)])
+ + HeaderPostamble())
+
+
+def UnitTestPreamble():
+ """Returns the preamble for the unit test file."""
+
+ # A map that defines the values used in the preamble template.
+ DEFS = {
+ 'today' : time.strftime('%m/%d/%Y'),
+ 'year' : time.strftime('%Y'),
+ 'command' : '%s %s' % (os.path.basename(sys.argv[0]), sys.argv[1]),
+ }
+
+ return (
+"""// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on %(today)s by command
+// '%(command)s'. DO NOT EDIT BY HAND!
+
+// Regression test for gtest_pred_impl.h
+//
+// This file is generated by a script and quite long. If you intend to
+// learn how Google Test works by reading its unit tests, read
+// gtest_unittest.cc instead.
+//
+// This is intended as a regression test for the Google Test predicate
+// assertions. We compile it as part of the gtest_unittest target
+// only to keep the implementation tidy and compact, as it is quite
+// involved to set up the stage for testing Google Test using Google
+// Test itself.
+//
+// Currently, gtest_unittest takes ~11 seconds to run in the testing
+// daemon. In the future, if it grows too large and needs much more
+// time to finish, we should consider separating this file into a
+// stand-alone regression test.
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+// A user-defined data type.
+struct Bool {
+ explicit Bool(int val) : value(val != 0) {}
+
+ bool operator>(int n) const { return value > Bool(n).value; }
+
+ Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); }
+
+ bool operator==(const Bool& rhs) const { return value == rhs.value; }
+
+ bool value;
+};
+
+// Enables Bool to be used in assertions.
+std::ostream& operator<<(std::ostream& os, const Bool& x) {
+ return os << (x.value ? "true" : "false");
+}
+
+""" % DEFS)
+
+
+def TestsForArity(n):
+ """Returns the tests for n-ary predicate assertions."""
+
+ # A map that defines the values used in the template for the tests.
+ DEFS = {
+ 'n' : n,
+ 'es' : Iter(n, 'e%s', sep=', '),
+ 'vs' : Iter(n, 'v%s', sep=', '),
+ 'vts' : Iter(n, '#v%s', sep=', '),
+ 'tvs' : Iter(n, 'T%s v%s', sep=', '),
+ 'int_vs' : Iter(n, 'int v%s', sep=', '),
+ 'Bool_vs' : Iter(n, 'Bool v%s', sep=', '),
+ 'types' : Iter(n, 'typename T%s', sep=', '),
+ 'v_sum' : Iter(n, 'v%s', sep=' + '),
+ 'arity' : Arity(n),
+ 'Arity' : Title(Arity(n)),
+ }
+
+ tests = (
+"""// Sample functions/functors for testing %(arity)s predicate assertions.
+
+// A %(arity)s predicate function.
+template <%(types)s>
+bool PredFunction%(n)s(%(tvs)s) {
+ return %(v_sum)s > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction%(n)sInt(%(int_vs)s) {
+ return %(v_sum)s > 0;
+}
+bool PredFunction%(n)sBool(%(Bool_vs)s) {
+ return %(v_sum)s > 0;
+}
+""" % DEFS)
+
+ tests += """
+// A %(arity)s predicate functor.
+struct PredFunctor%(n)s {
+ template <%(types)s>
+ bool operator()(""" % DEFS
+
+ tests += Iter(n, 'const T%s& v%s', sep=""",
+ """)
+
+ tests += """) {
+ return %(v_sum)s > 0;
+ }
+};
+""" % DEFS
+
+ tests += """
+// A %(arity)s predicate-formatter function.
+template <%(types)s>
+testing::AssertionResult PredFormatFunction%(n)s(""" % DEFS
+
+ tests += Iter(n, 'const char* e%s', sep=""",
+ """)
+
+ tests += Iter(n, """,
+ const T%s& v%s""")
+
+ tests += """) {
+ if (PredFunction%(n)s(%(vs)s))
+ return testing::AssertionSuccess();
+
+ testing::Message msg;
+ msg << """ % DEFS
+
+ tests += Iter(n, 'e%s', sep=' << " + " << ')
+
+ tests += """
+ << " is expected to be positive, but evaluates to "
+ << %(v_sum)s << ".";
+ return testing::AssertionFailure(msg);
+}
+""" % DEFS
+
+ tests += """
+// A %(arity)s predicate-formatter functor.
+struct PredFormatFunctor%(n)s {
+ template <%(types)s>
+ testing::AssertionResult operator()(""" % DEFS
+
+ tests += Iter(n, 'const char* e%s', sep=""",
+ """)
+
+ tests += Iter(n, """,
+ const T%s& v%s""")
+
+ tests += """) const {
+ return PredFormatFunction%(n)s(%(es)s, %(vs)s);
+ }
+};
+""" % DEFS
+
+ tests += """
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT%(n)s.
+
+class Predicate%(n)sTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;""" % DEFS
+
+ tests += """
+ """ + Iter(n, 'n%s_ = ') + """0;
+ }
+"""
+
+ tests += """
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once."""
+
+ tests += ''.join(["""
+ EXPECT_EQ(1, n%s_) <<
+ "The predicate assertion didn't evaluate argument %s "
+ "exactly once.";""" % (i, i + 1) for i in OneTo(n)])
+
+ tests += """
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+""" % DEFS
+
+ tests += Iter(n, """
+ static int n%s_;""")
+
+ tests += """
+};
+
+bool Predicate%(n)sTest::expected_to_finish_;
+bool Predicate%(n)sTest::finished_;
+""" % DEFS
+
+ tests += Iter(n, """int Predicate%%(n)sTest::n%s_;
+""") % DEFS
+
+ tests += """
+typedef Predicate%(n)sTest EXPECT_PRED_FORMAT%(n)sTest;
+typedef Predicate%(n)sTest ASSERT_PRED_FORMAT%(n)sTest;
+typedef Predicate%(n)sTest EXPECT_PRED%(n)sTest;
+typedef Predicate%(n)sTest ASSERT_PRED%(n)sTest;
+""" % DEFS
+
+ def GenTest(use_format, use_assert, expect_failure,
+ use_functor, use_user_type):
+ """Returns the test for a predicate assertion macro.
+
+ Args:
+ use_format: true iff the assertion is a *_PRED_FORMAT*.
+ use_assert: true iff the assertion is a ASSERT_*.
+ expect_failure: true iff the assertion is expected to fail.
+ use_functor: true iff the first argument of the assertion is
+ a functor (as opposed to a function)
+ use_user_type: true iff the predicate functor/function takes
+ argument(s) of a user-defined type.
+
+ Example:
+
+ GenTest(1, 0, 0, 1, 0) returns a test that tests the behavior
+ of a successful EXPECT_PRED_FORMATn() that takes a functor
+ whose arguments have built-in types."""
+
+ if use_assert:
+ assrt = 'ASSERT' # 'assert' is reserved, so we cannot use
+ # that identifier here.
+ else:
+ assrt = 'EXPECT'
+
+ assertion = assrt + '_PRED'
+
+ if use_format:
+ pred_format = 'PredFormat'
+ assertion += '_FORMAT'
+ else:
+ pred_format = 'Pred'
+
+ assertion += '%(n)s' % DEFS
+
+ if use_functor:
+ pred_format_type = 'functor'
+ pred_format += 'Functor%(n)s()'
+ else:
+ pred_format_type = 'function'
+ pred_format += 'Function%(n)s'
+ if not use_format:
+ if use_user_type:
+ pred_format += 'Bool'
+ else:
+ pred_format += 'Int'
+
+ test_name = pred_format_type.title()
+
+ if use_user_type:
+ arg_type = 'user-defined type (Bool)'
+ test_name += 'OnUserType'
+ if expect_failure:
+ arg = 'Bool(n%s_++)'
+ else:
+ arg = 'Bool(++n%s_)'
+ else:
+ arg_type = 'built-in type (int)'
+ test_name += 'OnBuiltInType'
+ if expect_failure:
+ arg = 'n%s_++'
+ else:
+ arg = '++n%s_'
+
+ if expect_failure:
+ successful_or_failed = 'failed'
+ expected_or_not = 'expected.'
+ test_name += 'Failure'
+ else:
+ successful_or_failed = 'successful'
+ expected_or_not = 'UNEXPECTED!'
+ test_name += 'Success'
+
+ # A map that defines the values used in the test template.
+ defs = DEFS.copy()
+ defs.update({
+ 'assert' : assrt,
+ 'assertion' : assertion,
+ 'test_name' : test_name,
+ 'pf_type' : pred_format_type,
+ 'pf' : pred_format,
+ 'arg_type' : arg_type,
+ 'arg' : arg,
+ 'successful' : successful_or_failed,
+ 'expected' : expected_or_not,
+ })
+
+ test = """
+// Tests a %(successful)s %(assertion)s where the
+// predicate-formatter is a %(pf_type)s on a %(arg_type)s.
+TEST_F(%(assertion)sTest, %(test_name)s) {""" % defs
+
+ indent = (len(assertion) + 3)*' '
+ extra_indent = ''
+
+ if expect_failure:
+ extra_indent = ' '
+ if use_assert:
+ test += """
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT"""
+ else:
+ test += """
+ EXPECT_NONFATAL_FAILURE({ // NOLINT"""
+
+ test += '\n' + extra_indent + """ %(assertion)s(%(pf)s""" % defs
+
+ test = test % defs
+ test += Iter(n, ',\n' + indent + extra_indent + '%(arg)s' % defs)
+ test += ');\n' + extra_indent + ' finished_ = true;\n'
+
+ if expect_failure:
+ test += ' }, "");\n'
+
+ test += '}\n'
+ return test
+
+ # Generates tests for all 2**6 = 64 combinations.
+ tests += ''.join([GenTest(use_format, use_assert, expect_failure,
+ use_functor, use_user_type)
+ for use_format in [0, 1]
+ for use_assert in [0, 1]
+ for expect_failure in [0, 1]
+ for use_functor in [0, 1]
+ for use_user_type in [0, 1]
+ ])
+
+ return tests
+
+
+def UnitTestPostamble():
+ """Returns the postamble for the tests."""
+
+ return ''
+
+
+def GenerateUnitTest(n):
+ """Returns the tests for up-to n-ary predicate assertions."""
+
+ GenerateFile(UNIT_TEST,
+ UnitTestPreamble()
+ + ''.join([TestsForArity(i) for i in OneTo(n)])
+ + UnitTestPostamble())
+
+
+def _Main():
+ """The entry point of the script. Generates the header file and its
+ unit test."""
+
+ if len(sys.argv) != 2:
+ print __doc__
+ print 'Author: ' + __author__
+ sys.exit(1)
+
+ n = int(sys.argv[1])
+ GenerateHeader(n)
+ GenerateUnitTest(n)
+
+
+if __name__ == '__main__':
+ _Main()
diff --git a/Source/ThirdParty/gtest/scripts/gtest-config.in b/Source/ThirdParty/gtest/scripts/gtest-config.in
new file mode 100755
index 000000000..9c7263854
--- /dev/null
+++ b/Source/ThirdParty/gtest/scripts/gtest-config.in
@@ -0,0 +1,274 @@
+#!/bin/sh
+
+# These variables are automatically filled in by the configure script.
+name="@PACKAGE_TARNAME@"
+version="@PACKAGE_VERSION@"
+
+show_usage()
+{
+ echo "Usage: gtest-config [OPTIONS...]"
+}
+
+show_help()
+{
+ show_usage
+ cat <<\EOF
+
+The `gtest-config' script provides access to the necessary compile and linking
+flags to connect with Google C++ Testing Framework, both in a build prior to
+installation, and on the system proper after installation. The installation
+overrides may be issued in combination with any other queries, but will only
+affect installation queries if called on a built but not installed gtest. The
+installation queries may not be issued with any other types of queries, and
+only one installation query may be made at a time. The version queries and
+compiler flag queries may be combined as desired but not mixed. Different
+version queries are always combined with logical "and" semantics, and only the
+last of any particular query is used while all previous ones ignored. All
+versions must be specified as a sequence of numbers separated by periods.
+Compiler flag queries output the union of the sets of flags when combined.
+
+ Examples:
+ gtest-config --min-version=1.0 || echo "Insufficient Google Test version."
+
+ g++ $(gtest-config --cppflags --cxxflags) -o foo.o -c foo.cpp
+ g++ $(gtest-config --ldflags --libs) -o foo foo.o
+
+ # When using a built but not installed Google Test:
+ g++ $(../../my_gtest_build/scripts/gtest-config ...) ...
+
+ # When using an installed Google Test, but with installation overrides:
+ export GTEST_PREFIX="/opt"
+ g++ $(gtest-config --libdir="/opt/lib64" ...) ...
+
+ Help:
+ --usage brief usage information
+ --help display this help message
+
+ Installation Overrides:
+ --prefix=<dir> overrides the installation prefix
+ --exec-prefix=<dir> overrides the executable installation prefix
+ --libdir=<dir> overrides the library installation prefix
+ --includedir=<dir> overrides the header file installation prefix
+
+ Installation Queries:
+ --prefix installation prefix
+ --exec-prefix executable installation prefix
+ --libdir library installation directory
+ --includedir header file installation directory
+ --version the version of the Google Test installation
+
+ Version Queries:
+ --min-version=VERSION return 0 if the version is at least VERSION
+ --exact-version=VERSION return 0 if the version is exactly VERSION
+ --max-version=VERSION return 0 if the version is at most VERSION
+
+ Compilation Flag Queries:
+ --cppflags compile flags specific to the C-like preprocessors
+ --cxxflags compile flags appropriate for C++ programs
+ --ldflags linker flags
+ --libs libraries for linking
+
+EOF
+}
+
+# This function bounds our version with a min and a max. It uses some clever
+# POSIX-compliant variable expansion to portably do all the work in the shell
+# and avoid any dependency on a particular "sed" or "awk" implementation.
+# Notable is that it will only ever compare the first 3 components of versions.
+# Further components will be cleanly stripped off. All versions must be
+# unadorned, so "v1.0" will *not* work. The minimum version must be in $1, and
+# the max in $2. TODO(chandlerc@google.com): If this ever breaks, we should
+# investigate expanding this via autom4te from AS_VERSION_COMPARE rather than
+# continuing to maintain our own shell version.
+check_versions()
+{
+ major_version=${version%%.*}
+ minor_version="0"
+ point_version="0"
+ if test "${version#*.}" != "${version}"; then
+ minor_version=${version#*.}
+ minor_version=${minor_version%%.*}
+ fi
+ if test "${version#*.*.}" != "${version}"; then
+ point_version=${version#*.*.}
+ point_version=${point_version%%.*}
+ fi
+
+ min_version="$1"
+ min_major_version=${min_version%%.*}
+ min_minor_version="0"
+ min_point_version="0"
+ if test "${min_version#*.}" != "${min_version}"; then
+ min_minor_version=${min_version#*.}
+ min_minor_version=${min_minor_version%%.*}
+ fi
+ if test "${min_version#*.*.}" != "${min_version}"; then
+ min_point_version=${min_version#*.*.}
+ min_point_version=${min_point_version%%.*}
+ fi
+
+ max_version="$2"
+ max_major_version=${max_version%%.*}
+ max_minor_version="0"
+ max_point_version="0"
+ if test "${max_version#*.}" != "${max_version}"; then
+ max_minor_version=${max_version#*.}
+ max_minor_version=${max_minor_version%%.*}
+ fi
+ if test "${max_version#*.*.}" != "${max_version}"; then
+ max_point_version=${max_version#*.*.}
+ max_point_version=${max_point_version%%.*}
+ fi
+
+ test $(($major_version)) -lt $(($min_major_version)) && exit 1
+ if test $(($major_version)) -eq $(($min_major_version)); then
+ test $(($minor_version)) -lt $(($min_minor_version)) && exit 1
+ if test $(($minor_version)) -eq $(($min_minor_version)); then
+ test $(($point_version)) -lt $(($min_point_version)) && exit 1
+ fi
+ fi
+
+ test $(($major_version)) -gt $(($max_major_version)) && exit 1
+ if test $(($major_version)) -eq $(($max_major_version)); then
+ test $(($minor_version)) -gt $(($max_minor_version)) && exit 1
+ if test $(($minor_version)) -eq $(($max_minor_version)); then
+ test $(($point_version)) -gt $(($max_point_version)) && exit 1
+ fi
+ fi
+
+ exit 0
+}
+
+# Show the usage line when no arguments are specified.
+if test $# -eq 0; then
+ show_usage
+ exit 1
+fi
+
+while test $# -gt 0; do
+ case $1 in
+ --usage) show_usage; exit 0;;
+ --help) show_help; exit 0;;
+
+ # Installation overrides
+ --prefix=*) GTEST_PREFIX=${1#--prefix=};;
+ --exec-prefix=*) GTEST_EXEC_PREFIX=${1#--exec-prefix=};;
+ --libdir=*) GTEST_LIBDIR=${1#--libdir=};;
+ --includedir=*) GTEST_INCLUDEDIR=${1#--includedir=};;
+
+ # Installation queries
+ --prefix|--exec-prefix|--libdir|--includedir|--version)
+ if test -n "${do_query}"; then
+ show_usage
+ exit 1
+ fi
+ do_query=${1#--}
+ ;;
+
+ # Version checking
+ --min-version=*)
+ do_check_versions=yes
+ min_version=${1#--min-version=}
+ ;;
+ --max-version=*)
+ do_check_versions=yes
+ max_version=${1#--max-version=}
+ ;;
+ --exact-version=*)
+ do_check_versions=yes
+ exact_version=${1#--exact-version=}
+ ;;
+
+ # Compiler flag output
+ --cppflags) echo_cppflags=yes;;
+ --cxxflags) echo_cxxflags=yes;;
+ --ldflags) echo_ldflags=yes;;
+ --libs) echo_libs=yes;;
+
+ # Everything else is an error
+ *) show_usage; exit 1;;
+ esac
+ shift
+done
+
+# These have defaults filled in by the configure script but can also be
+# overridden by environment variables or command line parameters.
+prefix="${GTEST_PREFIX:-@prefix@}"
+exec_prefix="${GTEST_EXEC_PREFIX:-@exec_prefix@}"
+libdir="${GTEST_LIBDIR:-@libdir@}"
+includedir="${GTEST_INCLUDEDIR:-@includedir@}"
+
+# We try and detect if our binary is not located at its installed location. If
+# it's not, we provide variables pointing to the source and build tree rather
+# than to the install tree. This allows building against a just-built gtest
+# rather than an installed gtest.
+bindir="@bindir@"
+this_relative_bindir=`dirname $0`
+this_bindir=`cd ${this_relative_bindir}; pwd -P`
+if test "${this_bindir}" = "${this_bindir%${bindir}}"; then
+ # The path to the script doesn't end in the bindir sequence from Autoconf,
+ # assume that we are in a build tree.
+ build_dir=`dirname ${this_bindir}`
+ src_dir=`cd ${this_bindir}/@top_srcdir@; pwd -P`
+
+ # TODO(chandlerc@google.com): This is a dangerous dependency on libtool, we
+ # should work to remove it, and/or remove libtool altogether, replacing it
+ # with direct references to the library and a link path.
+ gtest_libs="${build_dir}/lib/libgtest.la @PTHREAD_CFLAGS@ @PTHREAD_LIBS@"
+ gtest_ldflags=""
+
+ # We provide hooks to include from either the source or build dir, where the
+ # build dir is always preferred. This will potentially allow us to write
+ # build rules for generated headers and have them automatically be preferred
+ # over provided versions.
+ gtest_cppflags="-I${build_dir}/include -I${src_dir}/include"
+ gtest_cxxflags="@PTHREAD_CFLAGS@"
+else
+ # We're using an installed gtest, although it may be staged under some
+ # prefix. Assume (as our own libraries do) that we can resolve the prefix,
+ # and are present in the dynamic link paths.
+ gtest_ldflags="-L${libdir}"
+ gtest_libs="-l${name} @PTHREAD_CFLAGS@ @PTHREAD_LIBS@"
+ gtest_cppflags="-I${includedir}"
+ gtest_cxxflags="@PTHREAD_CFLAGS@"
+fi
+
+# Do an installation query if requested.
+if test -n "$do_query"; then
+ case $do_query in
+ prefix) echo $prefix; exit 0;;
+ exec-prefix) echo $exec_prefix; exit 0;;
+ libdir) echo $libdir; exit 0;;
+ includedir) echo $includedir; exit 0;;
+ version) echo $version; exit 0;;
+ *) show_usage; exit 1;;
+ esac
+fi
+
+# Do a version check if requested.
+if test "$do_check_versions" = "yes"; then
+ # Make sure we didn't receive a bad combination of parameters.
+ test "$echo_cppflags" = "yes" && show_usage && exit 1
+ test "$echo_cxxflags" = "yes" && show_usage && exit 1
+ test "$echo_ldflags" = "yes" && show_usage && exit 1
+ test "$echo_libs" = "yes" && show_usage && exit 1
+
+ if test "$exact_version" != ""; then
+ check_versions $exact_version $exact_version
+ # unreachable
+ else
+ check_versions ${min_version:-0.0.0} ${max_version:-9999.9999.9999}
+ # unreachable
+ fi
+fi
+
+# Do the output in the correct order so that these can be used in-line of
+# a compiler invocation.
+output=""
+test "$echo_cppflags" = "yes" && output="$output $gtest_cppflags"
+test "$echo_cxxflags" = "yes" && output="$output $gtest_cxxflags"
+test "$echo_ldflags" = "yes" && output="$output $gtest_ldflags"
+test "$echo_libs" = "yes" && output="$output $gtest_libs"
+echo $output
+
+exit 0
diff --git a/Source/ThirdParty/gtest/scripts/pump.py b/Source/ThirdParty/gtest/scripts/pump.py
new file mode 100755
index 000000000..f15c1b6ce
--- /dev/null
+++ b/Source/ThirdParty/gtest/scripts/pump.py
@@ -0,0 +1,835 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""pump v0.1 - Pretty Useful for Meta Programming.
+
+A tool for preprocessor meta programming. Useful for generating
+repetitive boilerplate code. Especially useful for writing C++
+classes, functions, macros, and templates that need to work with
+various number of arguments.
+
+USAGE:
+ pump.py SOURCE_FILE
+
+EXAMPLES:
+ pump.py foo.cc.pump
+ Converts foo.cc.pump to foo.cc.
+
+GRAMMAR:
+ CODE ::= ATOMIC_CODE*
+ ATOMIC_CODE ::= $var ID = EXPRESSION
+ | $var ID = [[ CODE ]]
+ | $range ID EXPRESSION..EXPRESSION
+ | $for ID SEPARATOR [[ CODE ]]
+ | $($)
+ | $ID
+ | $(EXPRESSION)
+ | $if EXPRESSION [[ CODE ]] ELSE_BRANCH
+ | [[ CODE ]]
+ | RAW_CODE
+ SEPARATOR ::= RAW_CODE | EMPTY
+ ELSE_BRANCH ::= $else [[ CODE ]]
+ | $elif EXPRESSION [[ CODE ]] ELSE_BRANCH
+ | EMPTY
+ EXPRESSION has Python syntax.
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import re
+import sys
+
+
+TOKEN_TABLE = [
+ (re.compile(r'\$var\s+'), '$var'),
+ (re.compile(r'\$elif\s+'), '$elif'),
+ (re.compile(r'\$else\s+'), '$else'),
+ (re.compile(r'\$for\s+'), '$for'),
+ (re.compile(r'\$if\s+'), '$if'),
+ (re.compile(r'\$range\s+'), '$range'),
+ (re.compile(r'\$[_A-Za-z]\w*'), '$id'),
+ (re.compile(r'\$\(\$\)'), '$($)'),
+ (re.compile(r'\$\$.*'), '$$'),
+ (re.compile(r'\$'), '$'),
+ (re.compile(r'\[\[\n?'), '[['),
+ (re.compile(r'\]\]\n?'), ']]'),
+ ]
+
+
+class Cursor:
+ """Represents a position (line and column) in a text file."""
+
+ def __init__(self, line=-1, column=-1):
+ self.line = line
+ self.column = column
+
+ def __eq__(self, rhs):
+ return self.line == rhs.line and self.column == rhs.column
+
+ def __ne__(self, rhs):
+ return not self == rhs
+
+ def __lt__(self, rhs):
+ return self.line < rhs.line or (
+ self.line == rhs.line and self.column < rhs.column)
+
+ def __le__(self, rhs):
+ return self < rhs or self == rhs
+
+ def __gt__(self, rhs):
+ return rhs < self
+
+ def __ge__(self, rhs):
+ return rhs <= self
+
+ def __str__(self):
+ if self == Eof():
+ return 'EOF'
+ else:
+ return '%s(%s)' % (self.line + 1, self.column)
+
+ def __add__(self, offset):
+ return Cursor(self.line, self.column + offset)
+
+ def __sub__(self, offset):
+ return Cursor(self.line, self.column - offset)
+
+ def Clone(self):
+ """Returns a copy of self."""
+
+ return Cursor(self.line, self.column)
+
+
+# Special cursor to indicate the end-of-file.
+def Eof():
+ """Returns the special cursor to denote the end-of-file."""
+ return Cursor(-1, -1)
+
+
+class Token:
+ """Represents a token in a Pump source file."""
+
+ def __init__(self, start=None, end=None, value=None, token_type=None):
+ if start is None:
+ self.start = Eof()
+ else:
+ self.start = start
+ if end is None:
+ self.end = Eof()
+ else:
+ self.end = end
+ self.value = value
+ self.token_type = token_type
+
+ def __str__(self):
+ return 'Token @%s: \'%s\' type=%s' % (
+ self.start, self.value, self.token_type)
+
+ def Clone(self):
+ """Returns a copy of self."""
+
+ return Token(self.start.Clone(), self.end.Clone(), self.value,
+ self.token_type)
+
+
+def StartsWith(lines, pos, string):
+ """Returns True iff the given position in lines starts with 'string'."""
+
+ return lines[pos.line][pos.column:].startswith(string)
+
+
+def FindFirstInLine(line, token_table):
+ best_match_start = -1
+ for (regex, token_type) in token_table:
+ m = regex.search(line)
+ if m:
+ # We found regex in lines
+ if best_match_start < 0 or m.start() < best_match_start:
+ best_match_start = m.start()
+ best_match_length = m.end() - m.start()
+ best_match_token_type = token_type
+
+ if best_match_start < 0:
+ return None
+
+ return (best_match_start, best_match_length, best_match_token_type)
+
+
+def FindFirst(lines, token_table, cursor):
+ """Finds the first occurrence of any string in strings in lines."""
+
+ start = cursor.Clone()
+ cur_line_number = cursor.line
+ for line in lines[start.line:]:
+ if cur_line_number == start.line:
+ line = line[start.column:]
+ m = FindFirstInLine(line, token_table)
+ if m:
+ # We found a regex in line.
+ (start_column, length, token_type) = m
+ if cur_line_number == start.line:
+ start_column += start.column
+ found_start = Cursor(cur_line_number, start_column)
+ found_end = found_start + length
+ return MakeToken(lines, found_start, found_end, token_type)
+ cur_line_number += 1
+ # We failed to find str in lines
+ return None
+
+
+def SubString(lines, start, end):
+ """Returns a substring in lines."""
+
+ if end == Eof():
+ end = Cursor(len(lines) - 1, len(lines[-1]))
+
+ if start >= end:
+ return ''
+
+ if start.line == end.line:
+ return lines[start.line][start.column:end.column]
+
+ result_lines = ([lines[start.line][start.column:]] +
+ lines[start.line + 1:end.line] +
+ [lines[end.line][:end.column]])
+ return ''.join(result_lines)
+
+
+def MakeToken(lines, start, end, token_type):
+ """Creates a new instance of Token."""
+
+ return Token(start, end, SubString(lines, start, end), token_type)
+
+
+def ParseToken(lines, pos, regex, token_type):
+ line = lines[pos.line][pos.column:]
+ m = regex.search(line)
+ if m and not m.start():
+ return MakeToken(lines, pos, pos + m.end(), token_type)
+ else:
+ print 'ERROR: %s expected at %s.' % (token_type, pos)
+ sys.exit(1)
+
+
+ID_REGEX = re.compile(r'[_A-Za-z]\w*')
+EQ_REGEX = re.compile(r'=')
+REST_OF_LINE_REGEX = re.compile(r'.*?(?=$|\$\$)')
+OPTIONAL_WHITE_SPACES_REGEX = re.compile(r'\s*')
+WHITE_SPACE_REGEX = re.compile(r'\s')
+DOT_DOT_REGEX = re.compile(r'\.\.')
+
+
+def Skip(lines, pos, regex):
+ line = lines[pos.line][pos.column:]
+ m = re.search(regex, line)
+ if m and not m.start():
+ return pos + m.end()
+ else:
+ return pos
+
+
+def SkipUntil(lines, pos, regex, token_type):
+ line = lines[pos.line][pos.column:]
+ m = re.search(regex, line)
+ if m:
+ return pos + m.start()
+ else:
+ print ('ERROR: %s expected on line %s after column %s.' %
+ (token_type, pos.line + 1, pos.column))
+ sys.exit(1)
+
+
+def ParseExpTokenInParens(lines, pos):
+ def ParseInParens(pos):
+ pos = Skip(lines, pos, OPTIONAL_WHITE_SPACES_REGEX)
+ pos = Skip(lines, pos, r'\(')
+ pos = Parse(pos)
+ pos = Skip(lines, pos, r'\)')
+ return pos
+
+ def Parse(pos):
+ pos = SkipUntil(lines, pos, r'\(|\)', ')')
+ if SubString(lines, pos, pos + 1) == '(':
+ pos = Parse(pos + 1)
+ pos = Skip(lines, pos, r'\)')
+ return Parse(pos)
+ else:
+ return pos
+
+ start = pos.Clone()
+ pos = ParseInParens(pos)
+ return MakeToken(lines, start, pos, 'exp')
+
+
+def RStripNewLineFromToken(token):
+ if token.value.endswith('\n'):
+ return Token(token.start, token.end, token.value[:-1], token.token_type)
+ else:
+ return token
+
+
+def TokenizeLines(lines, pos):
+ while True:
+ found = FindFirst(lines, TOKEN_TABLE, pos)
+ if not found:
+ yield MakeToken(lines, pos, Eof(), 'code')
+ return
+
+ if found.start == pos:
+ prev_token = None
+ prev_token_rstripped = None
+ else:
+ prev_token = MakeToken(lines, pos, found.start, 'code')
+ prev_token_rstripped = RStripNewLineFromToken(prev_token)
+
+ if found.token_type == '$$': # A meta comment.
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ pos = Cursor(found.end.line + 1, 0)
+ elif found.token_type == '$var':
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ yield found
+ id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+ yield id_token
+ pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
+
+ eq_token = ParseToken(lines, pos, EQ_REGEX, '=')
+ yield eq_token
+ pos = Skip(lines, eq_token.end, r'\s*')
+
+ if SubString(lines, pos, pos + 2) != '[[':
+ exp_token = ParseToken(lines, pos, REST_OF_LINE_REGEX, 'exp')
+ yield exp_token
+ pos = Cursor(exp_token.end.line + 1, 0)
+ elif found.token_type == '$for':
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ yield found
+ id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+ yield id_token
+ pos = Skip(lines, id_token.end, WHITE_SPACE_REGEX)
+ elif found.token_type == '$range':
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ yield found
+ id_token = ParseToken(lines, found.end, ID_REGEX, 'id')
+ yield id_token
+ pos = Skip(lines, id_token.end, OPTIONAL_WHITE_SPACES_REGEX)
+
+ dots_pos = SkipUntil(lines, pos, DOT_DOT_REGEX, '..')
+ yield MakeToken(lines, pos, dots_pos, 'exp')
+ yield MakeToken(lines, dots_pos, dots_pos + 2, '..')
+ pos = dots_pos + 2
+ new_pos = Cursor(pos.line + 1, 0)
+ yield MakeToken(lines, pos, new_pos, 'exp')
+ pos = new_pos
+ elif found.token_type == '$':
+ if prev_token:
+ yield prev_token
+ yield found
+ exp_token = ParseExpTokenInParens(lines, found.end)
+ yield exp_token
+ pos = exp_token.end
+ elif (found.token_type == ']]' or found.token_type == '$if' or
+ found.token_type == '$elif' or found.token_type == '$else'):
+ if prev_token_rstripped:
+ yield prev_token_rstripped
+ yield found
+ pos = found.end
+ else:
+ if prev_token:
+ yield prev_token
+ yield found
+ pos = found.end
+
+
+def Tokenize(s):
+ lines = s.splitlines(True)
+ return TokenizeLines(lines, Cursor(0, 0))
+
+
+class CodeNode:
+ def __init__(self, atomic_code_list=None):
+ self.atomic_code = atomic_code_list
+
+
+class VarNode:
+ def __init__(self, identifier=None, atomic_code=None):
+ self.identifier = identifier
+ self.atomic_code = atomic_code
+
+
+class RangeNode:
+ def __init__(self, identifier=None, exp1=None, exp2=None):
+ self.identifier = identifier
+ self.exp1 = exp1
+ self.exp2 = exp2
+
+
+class ForNode:
+ def __init__(self, identifier=None, sep=None, code=None):
+ self.identifier = identifier
+ self.sep = sep
+ self.code = code
+
+
+class ElseNode:
+ def __init__(self, else_branch=None):
+ self.else_branch = else_branch
+
+
+class IfNode:
+ def __init__(self, exp=None, then_branch=None, else_branch=None):
+ self.exp = exp
+ self.then_branch = then_branch
+ self.else_branch = else_branch
+
+
+class RawCodeNode:
+ def __init__(self, token=None):
+ self.raw_code = token
+
+
+class LiteralDollarNode:
+ def __init__(self, token):
+ self.token = token
+
+
+class ExpNode:
+ def __init__(self, token, python_exp):
+ self.token = token
+ self.python_exp = python_exp
+
+
+def PopFront(a_list):
+ head = a_list[0]
+ a_list[:1] = []
+ return head
+
+
+def PushFront(a_list, elem):
+ a_list[:0] = [elem]
+
+
+def PopToken(a_list, token_type=None):
+ token = PopFront(a_list)
+ if token_type is not None and token.token_type != token_type:
+ print 'ERROR: %s expected at %s' % (token_type, token.start)
+ print 'ERROR: %s found instead' % (token,)
+ sys.exit(1)
+
+ return token
+
+
+def PeekToken(a_list):
+ if not a_list:
+ return None
+
+ return a_list[0]
+
+
+def ParseExpNode(token):
+ python_exp = re.sub(r'([_A-Za-z]\w*)', r'self.GetValue("\1")', token.value)
+ return ExpNode(token, python_exp)
+
+
+def ParseElseNode(tokens):
+ def Pop(token_type=None):
+ return PopToken(tokens, token_type)
+
+ next = PeekToken(tokens)
+ if not next:
+ return None
+ if next.token_type == '$else':
+ Pop('$else')
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ return code_node
+ elif next.token_type == '$elif':
+ Pop('$elif')
+ exp = Pop('code')
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ inner_else_node = ParseElseNode(tokens)
+ return CodeNode([IfNode(ParseExpNode(exp), code_node, inner_else_node)])
+ elif not next.value.strip():
+ Pop('code')
+ return ParseElseNode(tokens)
+ else:
+ return None
+
+
+def ParseAtomicCodeNode(tokens):
+ def Pop(token_type=None):
+ return PopToken(tokens, token_type)
+
+ head = PopFront(tokens)
+ t = head.token_type
+ if t == 'code':
+ return RawCodeNode(head)
+ elif t == '$var':
+ id_token = Pop('id')
+ Pop('=')
+ next = PeekToken(tokens)
+ if next.token_type == 'exp':
+ exp_token = Pop()
+ return VarNode(id_token, ParseExpNode(exp_token))
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ return VarNode(id_token, code_node)
+ elif t == '$for':
+ id_token = Pop('id')
+ next_token = PeekToken(tokens)
+ if next_token.token_type == 'code':
+ sep_token = next_token
+ Pop('code')
+ else:
+ sep_token = None
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ return ForNode(id_token, sep_token, code_node)
+ elif t == '$if':
+ exp_token = Pop('code')
+ Pop('[[')
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ else_node = ParseElseNode(tokens)
+ return IfNode(ParseExpNode(exp_token), code_node, else_node)
+ elif t == '$range':
+ id_token = Pop('id')
+ exp1_token = Pop('exp')
+ Pop('..')
+ exp2_token = Pop('exp')
+ return RangeNode(id_token, ParseExpNode(exp1_token),
+ ParseExpNode(exp2_token))
+ elif t == '$id':
+ return ParseExpNode(Token(head.start + 1, head.end, head.value[1:], 'id'))
+ elif t == '$($)':
+ return LiteralDollarNode(head)
+ elif t == '$':
+ exp_token = Pop('exp')
+ return ParseExpNode(exp_token)
+ elif t == '[[':
+ code_node = ParseCodeNode(tokens)
+ Pop(']]')
+ return code_node
+ else:
+ PushFront(tokens, head)
+ return None
+
+
+def ParseCodeNode(tokens):
+ atomic_code_list = []
+ while True:
+ if not tokens:
+ break
+ atomic_code_node = ParseAtomicCodeNode(tokens)
+ if atomic_code_node:
+ atomic_code_list.append(atomic_code_node)
+ else:
+ break
+ return CodeNode(atomic_code_list)
+
+
+def Convert(file_path):
+ s = file(file_path, 'r').read()
+ tokens = []
+ for token in Tokenize(s):
+ tokens.append(token)
+ code_node = ParseCodeNode(tokens)
+ return code_node
+
+
+class Env:
+ def __init__(self):
+ self.variables = []
+ self.ranges = []
+
+ def Clone(self):
+ clone = Env()
+ clone.variables = self.variables[:]
+ clone.ranges = self.ranges[:]
+ return clone
+
+ def PushVariable(self, var, value):
+ # If value looks like an int, store it as an int.
+ try:
+ int_value = int(value)
+ if ('%s' % int_value) == value:
+ value = int_value
+ except Exception:
+ pass
+ self.variables[:0] = [(var, value)]
+
+ def PopVariable(self):
+ self.variables[:1] = []
+
+ def PushRange(self, var, lower, upper):
+ self.ranges[:0] = [(var, lower, upper)]
+
+ def PopRange(self):
+ self.ranges[:1] = []
+
+ def GetValue(self, identifier):
+ for (var, value) in self.variables:
+ if identifier == var:
+ return value
+
+ print 'ERROR: meta variable %s is undefined.' % (identifier,)
+ sys.exit(1)
+
+ def EvalExp(self, exp):
+ try:
+ result = eval(exp.python_exp)
+ except Exception, e:
+ print 'ERROR: caught exception %s: %s' % (e.__class__.__name__, e)
+ print ('ERROR: failed to evaluate meta expression %s at %s' %
+ (exp.python_exp, exp.token.start))
+ sys.exit(1)
+ return result
+
+ def GetRange(self, identifier):
+ for (var, lower, upper) in self.ranges:
+ if identifier == var:
+ return (lower, upper)
+
+ print 'ERROR: range %s is undefined.' % (identifier,)
+ sys.exit(1)
+
+
+class Output:
+ def __init__(self):
+ self.string = ''
+
+ def GetLastLine(self):
+ index = self.string.rfind('\n')
+ if index < 0:
+ return ''
+
+ return self.string[index + 1:]
+
+ def Append(self, s):
+ self.string += s
+
+
+def RunAtomicCode(env, node, output):
+ if isinstance(node, VarNode):
+ identifier = node.identifier.value.strip()
+ result = Output()
+ RunAtomicCode(env.Clone(), node.atomic_code, result)
+ value = result.string
+ env.PushVariable(identifier, value)
+ elif isinstance(node, RangeNode):
+ identifier = node.identifier.value.strip()
+ lower = int(env.EvalExp(node.exp1))
+ upper = int(env.EvalExp(node.exp2))
+ env.PushRange(identifier, lower, upper)
+ elif isinstance(node, ForNode):
+ identifier = node.identifier.value.strip()
+ if node.sep is None:
+ sep = ''
+ else:
+ sep = node.sep.value
+ (lower, upper) = env.GetRange(identifier)
+ for i in range(lower, upper + 1):
+ new_env = env.Clone()
+ new_env.PushVariable(identifier, i)
+ RunCode(new_env, node.code, output)
+ if i != upper:
+ output.Append(sep)
+ elif isinstance(node, RawCodeNode):
+ output.Append(node.raw_code.value)
+ elif isinstance(node, IfNode):
+ cond = env.EvalExp(node.exp)
+ if cond:
+ RunCode(env.Clone(), node.then_branch, output)
+ elif node.else_branch is not None:
+ RunCode(env.Clone(), node.else_branch, output)
+ elif isinstance(node, ExpNode):
+ value = env.EvalExp(node)
+ output.Append('%s' % (value,))
+ elif isinstance(node, LiteralDollarNode):
+ output.Append('$')
+ elif isinstance(node, CodeNode):
+ RunCode(env.Clone(), node, output)
+ else:
+ print 'BAD'
+ print node
+ sys.exit(1)
+
+
+def RunCode(env, code_node, output):
+ for atomic_code in code_node.atomic_code:
+ RunAtomicCode(env, atomic_code, output)
+
+
+def IsComment(cur_line):
+ return '//' in cur_line
+
+
+def IsInPreprocessorDirevative(prev_lines, cur_line):
+ if cur_line.lstrip().startswith('#'):
+ return True
+ return prev_lines != [] and prev_lines[-1].endswith('\\')
+
+
+def WrapComment(line, output):
+ loc = line.find('//')
+ before_comment = line[:loc].rstrip()
+ if before_comment == '':
+ indent = loc
+ else:
+ output.append(before_comment)
+ indent = len(before_comment) - len(before_comment.lstrip())
+ prefix = indent*' ' + '// '
+ max_len = 80 - len(prefix)
+ comment = line[loc + 2:].strip()
+ segs = [seg for seg in re.split(r'(\w+\W*)', comment) if seg != '']
+ cur_line = ''
+ for seg in segs:
+ if len((cur_line + seg).rstrip()) < max_len:
+ cur_line += seg
+ else:
+ if cur_line.strip() != '':
+ output.append(prefix + cur_line.rstrip())
+ cur_line = seg.lstrip()
+ if cur_line.strip() != '':
+ output.append(prefix + cur_line.strip())
+
+
+def WrapCode(line, line_concat, output):
+ indent = len(line) - len(line.lstrip())
+ prefix = indent*' ' # Prefix of the current line
+ max_len = 80 - indent - len(line_concat) # Maximum length of the current line
+ new_prefix = prefix + 4*' ' # Prefix of a continuation line
+ new_max_len = max_len - 4 # Maximum length of a continuation line
+ # Prefers to wrap a line after a ',' or ';'.
+ segs = [seg for seg in re.split(r'([^,;]+[,;]?)', line.strip()) if seg != '']
+ cur_line = '' # The current line without leading spaces.
+ for seg in segs:
+ # If the line is still too long, wrap at a space.
+ while cur_line == '' and len(seg.strip()) > max_len:
+ seg = seg.lstrip()
+ split_at = seg.rfind(' ', 0, max_len)
+ output.append(prefix + seg[:split_at].strip() + line_concat)
+ seg = seg[split_at + 1:]
+ prefix = new_prefix
+ max_len = new_max_len
+
+ if len((cur_line + seg).rstrip()) < max_len:
+ cur_line = (cur_line + seg).lstrip()
+ else:
+ output.append(prefix + cur_line.rstrip() + line_concat)
+ prefix = new_prefix
+ max_len = new_max_len
+ cur_line = seg.lstrip()
+ if cur_line.strip() != '':
+ output.append(prefix + cur_line.strip())
+
+
+def WrapPreprocessorDirevative(line, output):
+ WrapCode(line, ' \\', output)
+
+
+def WrapPlainCode(line, output):
+ WrapCode(line, '', output)
+
+
+def IsHeaderGuardOrInclude(line):
+ return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or
+ re.match(r'^#include\s', line))
+
+
+def WrapLongLine(line, output):
+ line = line.rstrip()
+ if len(line) <= 80:
+ output.append(line)
+ elif IsComment(line):
+ if IsHeaderGuardOrInclude(line):
+ # The style guide made an exception to allow long header guard lines
+ # and includes.
+ output.append(line)
+ else:
+ WrapComment(line, output)
+ elif IsInPreprocessorDirevative(output, line):
+ if IsHeaderGuardOrInclude(line):
+ # The style guide made an exception to allow long header guard lines
+ # and includes.
+ output.append(line)
+ else:
+ WrapPreprocessorDirevative(line, output)
+ else:
+ WrapPlainCode(line, output)
+
+
+def BeautifyCode(string):
+ lines = string.splitlines()
+ output = []
+ for line in lines:
+ WrapLongLine(line, output)
+ output2 = [line.rstrip() for line in output]
+ return '\n'.join(output2) + '\n'
+
+
+def main(argv):
+ if len(argv) == 1:
+ print __doc__
+ sys.exit(1)
+
+ file_path = argv[-1]
+ ast = Convert(file_path)
+ output = Output()
+ RunCode(Env(), ast, output)
+ output_str = BeautifyCode(output.string)
+ if file_path.endswith('.pump'):
+ output_file_path = file_path[:-5]
+ else:
+ output_file_path = '-'
+ if output_file_path == '-':
+ print output_str,
+ else:
+ output_file = file(output_file_path, 'w')
+ output_file.write('// This file was GENERATED by command:\n')
+ output_file.write('// %s %s\n' %
+ (os.path.basename(__file__), os.path.basename(file_path)))
+ output_file.write('// DO NOT EDIT BY HAND!!!\n\n')
+ output_file.write(output_str)
+ output_file.close()
+
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/Source/ThirdParty/gtest/scripts/test/Makefile b/Source/ThirdParty/gtest/scripts/test/Makefile
new file mode 100644
index 000000000..ffc0c90ad
--- /dev/null
+++ b/Source/ThirdParty/gtest/scripts/test/Makefile
@@ -0,0 +1,57 @@
+# A Makefile for fusing Google Test and building a sample test against it.
+#
+# SYNOPSIS:
+#
+# make [all] - makes everything.
+# make TARGET - makes the given target.
+# make check - makes everything and runs the built sample test.
+# make clean - removes all files generated by make.
+
+# Points to the root of fused Google Test, relative to where this file is.
+FUSED_GTEST_DIR = output
+
+# Paths to the fused gtest files.
+FUSED_GTEST_H = $(FUSED_GTEST_DIR)/gtest/gtest.h
+FUSED_GTEST_ALL_CC = $(FUSED_GTEST_DIR)/gtest/gtest-all.cc
+
+# Where to find the sample test.
+SAMPLE_DIR = ../../samples
+
+# Where to find gtest_main.cc.
+GTEST_MAIN_CC = ../../src/gtest_main.cc
+
+# Flags passed to the preprocessor.
+CPPFLAGS += -I$(FUSED_GTEST_DIR)
+
+# Flags passed to the C++ compiler.
+CXXFLAGS += -g
+
+all : sample1_unittest
+
+check : all
+ ./sample1_unittest
+
+clean :
+ rm -rf $(FUSED_GTEST_DIR) sample1_unittest *.o
+
+$(FUSED_GTEST_H) :
+ ../fuse_gtest_files.py $(FUSED_GTEST_DIR)
+
+$(FUSED_GTEST_ALL_CC) :
+ ../fuse_gtest_files.py $(FUSED_GTEST_DIR)
+
+gtest-all.o : $(FUSED_GTEST_H) $(FUSED_GTEST_ALL_CC)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(FUSED_GTEST_DIR)/gtest/gtest-all.cc
+
+gtest_main.o : $(FUSED_GTEST_H) $(GTEST_MAIN_CC)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(GTEST_MAIN_CC)
+
+sample1.o : $(SAMPLE_DIR)/sample1.cc $(SAMPLE_DIR)/sample1.h
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1.cc
+
+sample1_unittest.o : $(SAMPLE_DIR)/sample1_unittest.cc \
+ $(SAMPLE_DIR)/sample1.h $(FUSED_GTEST_H)
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(SAMPLE_DIR)/sample1_unittest.cc
+
+sample1_unittest : sample1.o sample1_unittest.o gtest-all.o gtest_main.o
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) $^ -o $@
diff --git a/Source/ThirdParty/gtest/scripts/upload.py b/Source/ThirdParty/gtest/scripts/upload.py
new file mode 100755
index 000000000..6e6f9a147
--- /dev/null
+++ b/Source/ThirdParty/gtest/scripts/upload.py
@@ -0,0 +1,1387 @@
+#!/usr/bin/env python
+#
+# Copyright 2007 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Tool for uploading diffs from a version control system to the codereview app.
+
+Usage summary: upload.py [options] [-- diff_options]
+
+Diff options are passed to the diff command of the underlying system.
+
+Supported version control systems:
+ Git
+ Mercurial
+ Subversion
+
+It is important for Git/Mercurial users to specify a tree/node/branch to diff
+against by using the '--rev' option.
+"""
+# This code is derived from appcfg.py in the App Engine SDK (open source),
+# and from ASPN recipe #146306.
+
+import cookielib
+import getpass
+import logging
+import md5
+import mimetypes
+import optparse
+import os
+import re
+import socket
+import subprocess
+import sys
+import urllib
+import urllib2
+import urlparse
+
+try:
+ import readline
+except ImportError:
+ pass
+
+# The logging verbosity:
+# 0: Errors only.
+# 1: Status messages.
+# 2: Info logs.
+# 3: Debug logs.
+verbosity = 1
+
+# Max size of patch or base file.
+MAX_UPLOAD_SIZE = 900 * 1024
+
+
+def GetEmail(prompt):
+ """Prompts the user for their email address and returns it.
+
+ The last used email address is saved to a file and offered up as a suggestion
+ to the user. If the user presses enter without typing in anything the last
+ used email address is used. If the user enters a new address, it is saved
+ for next time we prompt.
+
+ """
+ last_email_file_name = os.path.expanduser("~/.last_codereview_email_address")
+ last_email = ""
+ if os.path.exists(last_email_file_name):
+ try:
+ last_email_file = open(last_email_file_name, "r")
+ last_email = last_email_file.readline().strip("\n")
+ last_email_file.close()
+ prompt += " [%s]" % last_email
+ except IOError, e:
+ pass
+ email = raw_input(prompt + ": ").strip()
+ if email:
+ try:
+ last_email_file = open(last_email_file_name, "w")
+ last_email_file.write(email)
+ last_email_file.close()
+ except IOError, e:
+ pass
+ else:
+ email = last_email
+ return email
+
+
+def StatusUpdate(msg):
+ """Print a status message to stdout.
+
+ If 'verbosity' is greater than 0, print the message.
+
+ Args:
+ msg: The string to print.
+ """
+ if verbosity > 0:
+ print msg
+
+
+def ErrorExit(msg):
+ """Print an error message to stderr and exit."""
+ print >>sys.stderr, msg
+ sys.exit(1)
+
+
+class ClientLoginError(urllib2.HTTPError):
+ """Raised to indicate there was an error authenticating with ClientLogin."""
+
+ def __init__(self, url, code, msg, headers, args):
+ urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
+ self.args = args
+ self.reason = args["Error"]
+
+
+class AbstractRpcServer(object):
+ """Provides a common interface for a simple RPC server."""
+
+ def __init__(self, host, auth_function, host_override=None, extra_headers={},
+ save_cookies=False):
+ """Creates a new HttpRpcServer.
+
+ Args:
+ host: The host to send requests to.
+ auth_function: A function that takes no arguments and returns an
+ (email, password) tuple when called. Will be called if authentication
+ is required.
+ host_override: The host header to send to the server (defaults to host).
+ extra_headers: A dict of extra headers to append to every request.
+ save_cookies: If True, save the authentication cookies to local disk.
+ If False, use an in-memory cookiejar instead. Subclasses must
+ implement this functionality. Defaults to False.
+ """
+ self.host = host
+ self.host_override = host_override
+ self.auth_function = auth_function
+ self.authenticated = False
+ self.extra_headers = extra_headers
+ self.save_cookies = save_cookies
+ self.opener = self._GetOpener()
+ if self.host_override:
+ logging.info("Server: %s; Host: %s", self.host, self.host_override)
+ else:
+ logging.info("Server: %s", self.host)
+
+ def _GetOpener(self):
+ """Returns an OpenerDirector for making HTTP requests.
+
+ Returns:
+ A urllib2.OpenerDirector object.
+ """
+ raise NotImplementedError()
+
+ def _CreateRequest(self, url, data=None):
+ """Creates a new urllib request."""
+ logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
+ req = urllib2.Request(url, data=data)
+ if self.host_override:
+ req.add_header("Host", self.host_override)
+ for key, value in self.extra_headers.iteritems():
+ req.add_header(key, value)
+ return req
+
+ def _GetAuthToken(self, email, password):
+ """Uses ClientLogin to authenticate the user, returning an auth token.
+
+ Args:
+ email: The user's email address
+ password: The user's password
+
+ Raises:
+ ClientLoginError: If there was an error authenticating with ClientLogin.
+ HTTPError: If there was some other form of HTTP error.
+
+ Returns:
+ The authentication token returned by ClientLogin.
+ """
+ account_type = "GOOGLE"
+ if self.host.endswith(".google.com"):
+ # Needed for use inside Google.
+ account_type = "HOSTED"
+ req = self._CreateRequest(
+ url="https://www.google.com/accounts/ClientLogin",
+ data=urllib.urlencode({
+ "Email": email,
+ "Passwd": password,
+ "service": "ah",
+ "source": "rietveld-codereview-upload",
+ "accountType": account_type,
+ }),
+ )
+ try:
+ response = self.opener.open(req)
+ response_body = response.read()
+ response_dict = dict(x.split("=")
+ for x in response_body.split("\n") if x)
+ return response_dict["Auth"]
+ except urllib2.HTTPError, e:
+ if e.code == 403:
+ body = e.read()
+ response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
+ raise ClientLoginError(req.get_full_url(), e.code, e.msg,
+ e.headers, response_dict)
+ else:
+ raise
+
+ def _GetAuthCookie(self, auth_token):
+ """Fetches authentication cookies for an authentication token.
+
+ Args:
+ auth_token: The authentication token returned by ClientLogin.
+
+ Raises:
+ HTTPError: If there was an error fetching the authentication cookies.
+ """
+ # This is a dummy value to allow us to identify when we're successful.
+ continue_location = "http://localhost/"
+ args = {"continue": continue_location, "auth": auth_token}
+ req = self._CreateRequest("http://%s/_ah/login?%s" %
+ (self.host, urllib.urlencode(args)))
+ try:
+ response = self.opener.open(req)
+ except urllib2.HTTPError, e:
+ response = e
+ if (response.code != 302 or
+ response.info()["location"] != continue_location):
+ raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg,
+ response.headers, response.fp)
+ self.authenticated = True
+
+ def _Authenticate(self):
+ """Authenticates the user.
+
+ The authentication process works as follows:
+ 1) We get a username and password from the user
+ 2) We use ClientLogin to obtain an AUTH token for the user
+ (see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
+ 3) We pass the auth token to /_ah/login on the server to obtain an
+ authentication cookie. If login was successful, it tries to redirect
+ us to the URL we provided.
+
+ If we attempt to access the upload API without first obtaining an
+ authentication cookie, it returns a 401 response and directs us to
+ authenticate ourselves with ClientLogin.
+ """
+ for i in range(3):
+ credentials = self.auth_function()
+ try:
+ auth_token = self._GetAuthToken(credentials[0], credentials[1])
+ except ClientLoginError, e:
+ if e.reason == "BadAuthentication":
+ print >>sys.stderr, "Invalid username or password."
+ continue
+ if e.reason == "CaptchaRequired":
+ print >>sys.stderr, (
+ "Please go to\n"
+ "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
+ "and verify you are a human. Then try again.")
+ break
+ if e.reason == "NotVerified":
+ print >>sys.stderr, "Account not verified."
+ break
+ if e.reason == "TermsNotAgreed":
+ print >>sys.stderr, "User has not agreed to TOS."
+ break
+ if e.reason == "AccountDeleted":
+ print >>sys.stderr, "The user account has been deleted."
+ break
+ if e.reason == "AccountDisabled":
+ print >>sys.stderr, "The user account has been disabled."
+ break
+ if e.reason == "ServiceDisabled":
+ print >>sys.stderr, ("The user's access to the service has been "
+ "disabled.")
+ break
+ if e.reason == "ServiceUnavailable":
+ print >>sys.stderr, "The service is not available; try again later."
+ break
+ raise
+ self._GetAuthCookie(auth_token)
+ return
+
+ def Send(self, request_path, payload=None,
+ content_type="application/octet-stream",
+ timeout=None,
+ **kwargs):
+ """Sends an RPC and returns the response.
+
+ Args:
+ request_path: The path to send the request to, eg /api/appversion/create.
+ payload: The body of the request, or None to send an empty request.
+ content_type: The Content-Type header to use.
+ timeout: timeout in seconds; default None i.e. no timeout.
+ (Note: for large requests on OS X, the timeout doesn't work right.)
+ kwargs: Any keyword arguments are converted into query string parameters.
+
+ Returns:
+ The response body, as a string.
+ """
+ # TODO: Don't require authentication. Let the server say
+ # whether it is necessary.
+ if not self.authenticated:
+ self._Authenticate()
+
+ old_timeout = socket.getdefaulttimeout()
+ socket.setdefaulttimeout(timeout)
+ try:
+ tries = 0
+ while True:
+ tries += 1
+ args = dict(kwargs)
+ url = "http://%s%s" % (self.host, request_path)
+ if args:
+ url += "?" + urllib.urlencode(args)
+ req = self._CreateRequest(url=url, data=payload)
+ req.add_header("Content-Type", content_type)
+ try:
+ f = self.opener.open(req)
+ response = f.read()
+ f.close()
+ return response
+ except urllib2.HTTPError, e:
+ if tries > 3:
+ raise
+ elif e.code == 401:
+ self._Authenticate()
+## elif e.code >= 500 and e.code < 600:
+## # Server Error - try again.
+## continue
+ else:
+ raise
+ finally:
+ socket.setdefaulttimeout(old_timeout)
+
+
+class HttpRpcServer(AbstractRpcServer):
+ """Provides a simplified RPC-style interface for HTTP requests."""
+
+ def _Authenticate(self):
+ """Save the cookie jar after authentication."""
+ super(HttpRpcServer, self)._Authenticate()
+ if self.save_cookies:
+ StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
+ self.cookie_jar.save()
+
+ def _GetOpener(self):
+ """Returns an OpenerDirector that supports cookies and ignores redirects.
+
+ Returns:
+ A urllib2.OpenerDirector object.
+ """
+ opener = urllib2.OpenerDirector()
+ opener.add_handler(urllib2.ProxyHandler())
+ opener.add_handler(urllib2.UnknownHandler())
+ opener.add_handler(urllib2.HTTPHandler())
+ opener.add_handler(urllib2.HTTPDefaultErrorHandler())
+ opener.add_handler(urllib2.HTTPSHandler())
+ opener.add_handler(urllib2.HTTPErrorProcessor())
+ if self.save_cookies:
+ self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies")
+ self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
+ if os.path.exists(self.cookie_file):
+ try:
+ self.cookie_jar.load()
+ self.authenticated = True
+ StatusUpdate("Loaded authentication cookies from %s" %
+ self.cookie_file)
+ except (cookielib.LoadError, IOError):
+ # Failed to load cookies - just ignore them.
+ pass
+ else:
+ # Create an empty cookie file with mode 600
+ fd = os.open(self.cookie_file, os.O_CREAT, 0600)
+ os.close(fd)
+ # Always chmod the cookie file
+ os.chmod(self.cookie_file, 0600)
+ else:
+ # Don't save cookies across runs of update.py.
+ self.cookie_jar = cookielib.CookieJar()
+ opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
+ return opener
+
+
+parser = optparse.OptionParser(usage="%prog [options] [-- diff_options]")
+parser.add_option("-y", "--assume_yes", action="store_true",
+ dest="assume_yes", default=False,
+ help="Assume that the answer to yes/no questions is 'yes'.")
+# Logging
+group = parser.add_option_group("Logging options")
+group.add_option("-q", "--quiet", action="store_const", const=0,
+ dest="verbose", help="Print errors only.")
+group.add_option("-v", "--verbose", action="store_const", const=2,
+ dest="verbose", default=1,
+ help="Print info level logs (default).")
+group.add_option("--noisy", action="store_const", const=3,
+ dest="verbose", help="Print all logs.")
+# Review server
+group = parser.add_option_group("Review server options")
+group.add_option("-s", "--server", action="store", dest="server",
+ default="codereview.appspot.com",
+ metavar="SERVER",
+ help=("The server to upload to. The format is host[:port]. "
+ "Defaults to 'codereview.appspot.com'."))
+group.add_option("-e", "--email", action="store", dest="email",
+ metavar="EMAIL", default=None,
+ help="The username to use. Will prompt if omitted.")
+group.add_option("-H", "--host", action="store", dest="host",
+ metavar="HOST", default=None,
+ help="Overrides the Host header sent with all RPCs.")
+group.add_option("--no_cookies", action="store_false",
+ dest="save_cookies", default=True,
+ help="Do not save authentication cookies to local disk.")
+# Issue
+group = parser.add_option_group("Issue options")
+group.add_option("-d", "--description", action="store", dest="description",
+ metavar="DESCRIPTION", default=None,
+ help="Optional description when creating an issue.")
+group.add_option("-f", "--description_file", action="store",
+ dest="description_file", metavar="DESCRIPTION_FILE",
+ default=None,
+ help="Optional path of a file that contains "
+ "the description when creating an issue.")
+group.add_option("-r", "--reviewers", action="store", dest="reviewers",
+ metavar="REVIEWERS", default=None,
+ help="Add reviewers (comma separated email addresses).")
+group.add_option("--cc", action="store", dest="cc",
+ metavar="CC", default=None,
+ help="Add CC (comma separated email addresses).")
+# Upload options
+group = parser.add_option_group("Patch options")
+group.add_option("-m", "--message", action="store", dest="message",
+ metavar="MESSAGE", default=None,
+ help="A message to identify the patch. "
+ "Will prompt if omitted.")
+group.add_option("-i", "--issue", type="int", action="store",
+ metavar="ISSUE", default=None,
+ help="Issue number to which to add. Defaults to new issue.")
+group.add_option("--download_base", action="store_true",
+ dest="download_base", default=False,
+ help="Base files will be downloaded by the server "
+ "(side-by-side diffs may not work on files with CRs).")
+group.add_option("--rev", action="store", dest="revision",
+ metavar="REV", default=None,
+ help="Branch/tree/revision to diff against (used by DVCS).")
+group.add_option("--send_mail", action="store_true",
+ dest="send_mail", default=False,
+ help="Send notification email to reviewers.")
+
+
+def GetRpcServer(options):
+ """Returns an instance of an AbstractRpcServer.
+
+ Returns:
+ A new AbstractRpcServer, on which RPC calls can be made.
+ """
+
+ rpc_server_class = HttpRpcServer
+
+ def GetUserCredentials():
+ """Prompts the user for a username and password."""
+ email = options.email
+ if email is None:
+ email = GetEmail("Email (login for uploading to %s)" % options.server)
+ password = getpass.getpass("Password for %s: " % email)
+ return (email, password)
+
+ # If this is the dev_appserver, use fake authentication.
+ host = (options.host or options.server).lower()
+ if host == "localhost" or host.startswith("localhost:"):
+ email = options.email
+ if email is None:
+ email = "test@example.com"
+ logging.info("Using debug user %s. Override with --email" % email)
+ server = rpc_server_class(
+ options.server,
+ lambda: (email, "password"),
+ host_override=options.host,
+ extra_headers={"Cookie":
+ 'dev_appserver_login="%s:False"' % email},
+ save_cookies=options.save_cookies)
+ # Don't try to talk to ClientLogin.
+ server.authenticated = True
+ return server
+
+ return rpc_server_class(options.server, GetUserCredentials,
+ host_override=options.host,
+ save_cookies=options.save_cookies)
+
+
+def EncodeMultipartFormData(fields, files):
+ """Encode form fields for multipart/form-data.
+
+ Args:
+ fields: A sequence of (name, value) elements for regular form fields.
+ files: A sequence of (name, filename, value) elements for data to be
+ uploaded as files.
+ Returns:
+ (content_type, body) ready for httplib.HTTP instance.
+
+ Source:
+ http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
+ """
+ BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
+ CRLF = '\r\n'
+ lines = []
+ for (key, value) in fields:
+ lines.append('--' + BOUNDARY)
+ lines.append('Content-Disposition: form-data; name="%s"' % key)
+ lines.append('')
+ lines.append(value)
+ for (key, filename, value) in files:
+ lines.append('--' + BOUNDARY)
+ lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
+ (key, filename))
+ lines.append('Content-Type: %s' % GetContentType(filename))
+ lines.append('')
+ lines.append(value)
+ lines.append('--' + BOUNDARY + '--')
+ lines.append('')
+ body = CRLF.join(lines)
+ content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
+ return content_type, body
+
+
+def GetContentType(filename):
+ """Helper to guess the content-type from the filename."""
+ return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
+
+
+# Use a shell for subcommands on Windows to get a PATH search.
+use_shell = sys.platform.startswith("win")
+
+def RunShellWithReturnCode(command, print_output=False,
+ universal_newlines=True):
+ """Executes a command and returns the output from stdout and the return code.
+
+ Args:
+ command: Command to execute.
+ print_output: If True, the output is printed to stdout.
+ If False, both stdout and stderr are ignored.
+ universal_newlines: Use universal_newlines flag (default: True).
+
+ Returns:
+ Tuple (output, return code)
+ """
+ logging.info("Running %s", command)
+ p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ shell=use_shell, universal_newlines=universal_newlines)
+ if print_output:
+ output_array = []
+ while True:
+ line = p.stdout.readline()
+ if not line:
+ break
+ print line.strip("\n")
+ output_array.append(line)
+ output = "".join(output_array)
+ else:
+ output = p.stdout.read()
+ p.wait()
+ errout = p.stderr.read()
+ if print_output and errout:
+ print >>sys.stderr, errout
+ p.stdout.close()
+ p.stderr.close()
+ return output, p.returncode
+
+
+def RunShell(command, silent_ok=False, universal_newlines=True,
+ print_output=False):
+ data, retcode = RunShellWithReturnCode(command, print_output,
+ universal_newlines)
+ if retcode:
+ ErrorExit("Got error status from %s:\n%s" % (command, data))
+ if not silent_ok and not data:
+ ErrorExit("No output from %s" % command)
+ return data
+
+
+class VersionControlSystem(object):
+ """Abstract base class providing an interface to the VCS."""
+
+ def __init__(self, options):
+ """Constructor.
+
+ Args:
+ options: Command line options.
+ """
+ self.options = options
+
+ def GenerateDiff(self, args):
+ """Return the current diff as a string.
+
+ Args:
+ args: Extra arguments to pass to the diff command.
+ """
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+ def GetUnknownFiles(self):
+ """Return a list of files unknown to the VCS."""
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+ def CheckForUnknownFiles(self):
+ """Show an "are you sure?" prompt if there are unknown files."""
+ unknown_files = self.GetUnknownFiles()
+ if unknown_files:
+ print "The following files are not added to version control:"
+ for line in unknown_files:
+ print line
+ prompt = "Are you sure to continue?(y/N) "
+ answer = raw_input(prompt).strip()
+ if answer != "y":
+ ErrorExit("User aborted")
+
+ def GetBaseFile(self, filename):
+ """Get the content of the upstream version of a file.
+
+ Returns:
+ A tuple (base_content, new_content, is_binary, status)
+ base_content: The contents of the base file.
+ new_content: For text files, this is empty. For binary files, this is
+ the contents of the new file, since the diff output won't contain
+ information to reconstruct the current file.
+ is_binary: True iff the file is binary.
+ status: The status of the file.
+ """
+
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+
+ def GetBaseFiles(self, diff):
+ """Helper that calls GetBase file for each file in the patch.
+
+ Returns:
+ A dictionary that maps from filename to GetBaseFile's tuple. Filenames
+ are retrieved based on lines that start with "Index:" or
+ "Property changes on:".
+ """
+ files = {}
+ for line in diff.splitlines(True):
+ if line.startswith('Index:') or line.startswith('Property changes on:'):
+ unused, filename = line.split(':', 1)
+ # On Windows if a file has property changes its filename uses '\'
+ # instead of '/'.
+ filename = filename.strip().replace('\\', '/')
+ files[filename] = self.GetBaseFile(filename)
+ return files
+
+
+ def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options,
+ files):
+ """Uploads the base files (and if necessary, the current ones as well)."""
+
+ def UploadFile(filename, file_id, content, is_binary, status, is_base):
+ """Uploads a file to the server."""
+ file_too_large = False
+ if is_base:
+ type = "base"
+ else:
+ type = "current"
+ if len(content) > MAX_UPLOAD_SIZE:
+ print ("Not uploading the %s file for %s because it's too large." %
+ (type, filename))
+ file_too_large = True
+ content = ""
+ checksum = md5.new(content).hexdigest()
+ if options.verbose > 0 and not file_too_large:
+ print "Uploading %s file for %s" % (type, filename)
+ url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
+ form_fields = [("filename", filename),
+ ("status", status),
+ ("checksum", checksum),
+ ("is_binary", str(is_binary)),
+ ("is_current", str(not is_base)),
+ ]
+ if file_too_large:
+ form_fields.append(("file_too_large", "1"))
+ if options.email:
+ form_fields.append(("user", options.email))
+ ctype, body = EncodeMultipartFormData(form_fields,
+ [("data", filename, content)])
+ response_body = rpc_server.Send(url, body,
+ content_type=ctype)
+ if not response_body.startswith("OK"):
+ StatusUpdate(" --> %s" % response_body)
+ sys.exit(1)
+
+ patches = dict()
+ [patches.setdefault(v, k) for k, v in patch_list]
+ for filename in patches.keys():
+ base_content, new_content, is_binary, status = files[filename]
+ file_id_str = patches.get(filename)
+ if file_id_str.find("nobase") != -1:
+ base_content = None
+ file_id_str = file_id_str[file_id_str.rfind("_") + 1:]
+ file_id = int(file_id_str)
+ if base_content != None:
+ UploadFile(filename, file_id, base_content, is_binary, status, True)
+ if new_content != None:
+ UploadFile(filename, file_id, new_content, is_binary, status, False)
+
+ def IsImage(self, filename):
+ """Returns true if the filename has an image extension."""
+ mimetype = mimetypes.guess_type(filename)[0]
+ if not mimetype:
+ return False
+ return mimetype.startswith("image/")
+
+
+class SubversionVCS(VersionControlSystem):
+ """Implementation of the VersionControlSystem interface for Subversion."""
+
+ def __init__(self, options):
+ super(SubversionVCS, self).__init__(options)
+ if self.options.revision:
+ match = re.match(r"(\d+)(:(\d+))?", self.options.revision)
+ if not match:
+ ErrorExit("Invalid Subversion revision %s." % self.options.revision)
+ self.rev_start = match.group(1)
+ self.rev_end = match.group(3)
+ else:
+ self.rev_start = self.rev_end = None
+ # Cache output from "svn list -r REVNO dirname".
+ # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev).
+ self.svnls_cache = {}
+ # SVN base URL is required to fetch files deleted in an older revision.
+ # Result is cached to not guess it over and over again in GetBaseFile().
+ required = self.options.download_base or self.options.revision is not None
+ self.svn_base = self._GuessBase(required)
+
+ def GuessBase(self, required):
+ """Wrapper for _GuessBase."""
+ return self.svn_base
+
+ def _GuessBase(self, required):
+ """Returns the SVN base URL.
+
+ Args:
+ required: If true, exits if the url can't be guessed, otherwise None is
+ returned.
+ """
+ info = RunShell(["svn", "info"])
+ for line in info.splitlines():
+ words = line.split()
+ if len(words) == 2 and words[0] == "URL:":
+ url = words[1]
+ scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
+ username, netloc = urllib.splituser(netloc)
+ if username:
+ logging.info("Removed username from base URL")
+ if netloc.endswith("svn.python.org"):
+ if netloc == "svn.python.org":
+ if path.startswith("/projects/"):
+ path = path[9:]
+ elif netloc != "pythondev@svn.python.org":
+ ErrorExit("Unrecognized Python URL: %s" % url)
+ base = "http://svn.python.org/view/*checkout*%s/" % path
+ logging.info("Guessed Python base = %s", base)
+ elif netloc.endswith("svn.collab.net"):
+ if path.startswith("/repos/"):
+ path = path[6:]
+ base = "http://svn.collab.net/viewvc/*checkout*%s/" % path
+ logging.info("Guessed CollabNet base = %s", base)
+ elif netloc.endswith(".googlecode.com"):
+ path = path + "/"
+ base = urlparse.urlunparse(("http", netloc, path, params,
+ query, fragment))
+ logging.info("Guessed Google Code base = %s", base)
+ else:
+ path = path + "/"
+ base = urlparse.urlunparse((scheme, netloc, path, params,
+ query, fragment))
+ logging.info("Guessed base = %s", base)
+ return base
+ if required:
+ ErrorExit("Can't find URL in output from svn info")
+ return None
+
+ def GenerateDiff(self, args):
+ cmd = ["svn", "diff"]
+ if self.options.revision:
+ cmd += ["-r", self.options.revision]
+ cmd.extend(args)
+ data = RunShell(cmd)
+ count = 0
+ for line in data.splitlines():
+ if line.startswith("Index:") or line.startswith("Property changes on:"):
+ count += 1
+ logging.info(line)
+ if not count:
+ ErrorExit("No valid patches found in output from svn diff")
+ return data
+
+ def _CollapseKeywords(self, content, keyword_str):
+ """Collapses SVN keywords."""
+ # svn cat translates keywords but svn diff doesn't. As a result of this
+ # behavior patching.PatchChunks() fails with a chunk mismatch error.
+ # This part was originally written by the Review Board development team
+ # who had the same problem (http://reviews.review-board.org/r/276/).
+ # Mapping of keywords to known aliases
+ svn_keywords = {
+ # Standard keywords
+ 'Date': ['Date', 'LastChangedDate'],
+ 'Revision': ['Revision', 'LastChangedRevision', 'Rev'],
+ 'Author': ['Author', 'LastChangedBy'],
+ 'HeadURL': ['HeadURL', 'URL'],
+ 'Id': ['Id'],
+
+ # Aliases
+ 'LastChangedDate': ['LastChangedDate', 'Date'],
+ 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'],
+ 'LastChangedBy': ['LastChangedBy', 'Author'],
+ 'URL': ['URL', 'HeadURL'],
+ }
+
+ def repl(m):
+ if m.group(2):
+ return "$%s::%s$" % (m.group(1), " " * len(m.group(3)))
+ return "$%s$" % m.group(1)
+ keywords = [keyword
+ for name in keyword_str.split(" ")
+ for keyword in svn_keywords.get(name, [])]
+ return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content)
+
+ def GetUnknownFiles(self):
+ status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True)
+ unknown_files = []
+ for line in status.split("\n"):
+ if line and line[0] == "?":
+ unknown_files.append(line)
+ return unknown_files
+
+ def ReadFile(self, filename):
+ """Returns the contents of a file."""
+ file = open(filename, 'rb')
+ result = ""
+ try:
+ result = file.read()
+ finally:
+ file.close()
+ return result
+
+ def GetStatus(self, filename):
+ """Returns the status of a file."""
+ if not self.options.revision:
+ status = RunShell(["svn", "status", "--ignore-externals", filename])
+ if not status:
+ ErrorExit("svn status returned no output for %s" % filename)
+ status_lines = status.splitlines()
+ # If file is in a cl, the output will begin with
+ # "\n--- Changelist 'cl_name':\n". See
+ # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt
+ if (len(status_lines) == 3 and
+ not status_lines[0] and
+ status_lines[1].startswith("--- Changelist")):
+ status = status_lines[2]
+ else:
+ status = status_lines[0]
+ # If we have a revision to diff against we need to run "svn list"
+ # for the old and the new revision and compare the results to get
+ # the correct status for a file.
+ else:
+ dirname, relfilename = os.path.split(filename)
+ if dirname not in self.svnls_cache:
+ cmd = ["svn", "list", "-r", self.rev_start, dirname or "."]
+ out, returncode = RunShellWithReturnCode(cmd)
+ if returncode:
+ ErrorExit("Failed to get status for %s." % filename)
+ old_files = out.splitlines()
+ args = ["svn", "list"]
+ if self.rev_end:
+ args += ["-r", self.rev_end]
+ cmd = args + [dirname or "."]
+ out, returncode = RunShellWithReturnCode(cmd)
+ if returncode:
+ ErrorExit("Failed to run command %s" % cmd)
+ self.svnls_cache[dirname] = (old_files, out.splitlines())
+ old_files, new_files = self.svnls_cache[dirname]
+ if relfilename in old_files and relfilename not in new_files:
+ status = "D "
+ elif relfilename in old_files and relfilename in new_files:
+ status = "M "
+ else:
+ status = "A "
+ return status
+
+ def GetBaseFile(self, filename):
+ status = self.GetStatus(filename)
+ base_content = None
+ new_content = None
+
+ # If a file is copied its status will be "A +", which signifies
+ # "addition-with-history". See "svn st" for more information. We need to
+ # upload the original file or else diff parsing will fail if the file was
+ # edited.
+ if status[0] == "A" and status[3] != "+":
+ # We'll need to upload the new content if we're adding a binary file
+ # since diff's output won't contain it.
+ mimetype = RunShell(["svn", "propget", "svn:mime-type", filename],
+ silent_ok=True)
+ base_content = ""
+ is_binary = mimetype and not mimetype.startswith("text/")
+ if is_binary and self.IsImage(filename):
+ new_content = self.ReadFile(filename)
+ elif (status[0] in ("M", "D", "R") or
+ (status[0] == "A" and status[3] == "+") or # Copied file.
+ (status[0] == " " and status[1] == "M")): # Property change.
+ args = []
+ if self.options.revision:
+ url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+ else:
+ # Don't change filename, it's needed later.
+ url = filename
+ args += ["-r", "BASE"]
+ cmd = ["svn"] + args + ["propget", "svn:mime-type", url]
+ mimetype, returncode = RunShellWithReturnCode(cmd)
+ if returncode:
+ # File does not exist in the requested revision.
+ # Reset mimetype, it contains an error message.
+ mimetype = ""
+ get_base = False
+ is_binary = mimetype and not mimetype.startswith("text/")
+ if status[0] == " ":
+ # Empty base content just to force an upload.
+ base_content = ""
+ elif is_binary:
+ if self.IsImage(filename):
+ get_base = True
+ if status[0] == "M":
+ if not self.rev_end:
+ new_content = self.ReadFile(filename)
+ else:
+ url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end)
+ new_content = RunShell(["svn", "cat", url],
+ universal_newlines=True, silent_ok=True)
+ else:
+ base_content = ""
+ else:
+ get_base = True
+
+ if get_base:
+ if is_binary:
+ universal_newlines = False
+ else:
+ universal_newlines = True
+ if self.rev_start:
+ # "svn cat -r REV delete_file.txt" doesn't work. cat requires
+ # the full URL with "@REV" appended instead of using "-r" option.
+ url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+ base_content = RunShell(["svn", "cat", url],
+ universal_newlines=universal_newlines,
+ silent_ok=True)
+ else:
+ base_content = RunShell(["svn", "cat", filename],
+ universal_newlines=universal_newlines,
+ silent_ok=True)
+ if not is_binary:
+ args = []
+ if self.rev_start:
+ url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
+ else:
+ url = filename
+ args += ["-r", "BASE"]
+ cmd = ["svn"] + args + ["propget", "svn:keywords", url]
+ keywords, returncode = RunShellWithReturnCode(cmd)
+ if keywords and not returncode:
+ base_content = self._CollapseKeywords(base_content, keywords)
+ else:
+ StatusUpdate("svn status returned unexpected output: %s" % status)
+ sys.exit(1)
+ return base_content, new_content, is_binary, status[0:5]
+
+
+class GitVCS(VersionControlSystem):
+ """Implementation of the VersionControlSystem interface for Git."""
+
+ def __init__(self, options):
+ super(GitVCS, self).__init__(options)
+ # Map of filename -> hash of base file.
+ self.base_hashes = {}
+
+ def GenerateDiff(self, extra_args):
+ # This is more complicated than svn's GenerateDiff because we must convert
+ # the diff output to include an svn-style "Index:" line as well as record
+ # the hashes of the base files, so we can upload them along with our diff.
+ if self.options.revision:
+ extra_args = [self.options.revision] + extra_args
+ gitdiff = RunShell(["git", "diff", "--full-index"] + extra_args)
+ svndiff = []
+ filecount = 0
+ filename = None
+ for line in gitdiff.splitlines():
+ match = re.match(r"diff --git a/(.*) b/.*$", line)
+ if match:
+ filecount += 1
+ filename = match.group(1)
+ svndiff.append("Index: %s\n" % filename)
+ else:
+ # The "index" line in a git diff looks like this (long hashes elided):
+ # index 82c0d44..b2cee3f 100755
+ # We want to save the left hash, as that identifies the base file.
+ match = re.match(r"index (\w+)\.\.", line)
+ if match:
+ self.base_hashes[filename] = match.group(1)
+ svndiff.append(line + "\n")
+ if not filecount:
+ ErrorExit("No valid patches found in output from git diff")
+ return "".join(svndiff)
+
+ def GetUnknownFiles(self):
+ status = RunShell(["git", "ls-files", "--exclude-standard", "--others"],
+ silent_ok=True)
+ return status.splitlines()
+
+ def GetBaseFile(self, filename):
+ hash = self.base_hashes[filename]
+ base_content = None
+ new_content = None
+ is_binary = False
+ if hash == "0" * 40: # All-zero hash indicates no base file.
+ status = "A"
+ base_content = ""
+ else:
+ status = "M"
+ base_content, returncode = RunShellWithReturnCode(["git", "show", hash])
+ if returncode:
+ ErrorExit("Got error status from 'git show %s'" % hash)
+ return (base_content, new_content, is_binary, status)
+
+
+class MercurialVCS(VersionControlSystem):
+ """Implementation of the VersionControlSystem interface for Mercurial."""
+
+ def __init__(self, options, repo_dir):
+ super(MercurialVCS, self).__init__(options)
+ # Absolute path to repository (we can be in a subdir)
+ self.repo_dir = os.path.normpath(repo_dir)
+ # Compute the subdir
+ cwd = os.path.normpath(os.getcwd())
+ assert cwd.startswith(self.repo_dir)
+ self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/")
+ if self.options.revision:
+ self.base_rev = self.options.revision
+ else:
+ self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip()
+
+ def _GetRelPath(self, filename):
+ """Get relative path of a file according to the current directory,
+ given its logical path in the repo."""
+ assert filename.startswith(self.subdir), filename
+ return filename[len(self.subdir):].lstrip(r"\/")
+
+ def GenerateDiff(self, extra_args):
+ # If no file specified, restrict to the current subdir
+ extra_args = extra_args or ["."]
+ cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args
+ data = RunShell(cmd, silent_ok=True)
+ svndiff = []
+ filecount = 0
+ for line in data.splitlines():
+ m = re.match("diff --git a/(\S+) b/(\S+)", line)
+ if m:
+ # Modify line to make it look like as it comes from svn diff.
+ # With this modification no changes on the server side are required
+ # to make upload.py work with Mercurial repos.
+ # NOTE: for proper handling of moved/copied files, we have to use
+ # the second filename.
+ filename = m.group(2)
+ svndiff.append("Index: %s" % filename)
+ svndiff.append("=" * 67)
+ filecount += 1
+ logging.info(line)
+ else:
+ svndiff.append(line)
+ if not filecount:
+ ErrorExit("No valid patches found in output from hg diff")
+ return "\n".join(svndiff) + "\n"
+
+ def GetUnknownFiles(self):
+ """Return a list of files unknown to the VCS."""
+ args = []
+ status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."],
+ silent_ok=True)
+ unknown_files = []
+ for line in status.splitlines():
+ st, fn = line.split(" ", 1)
+ if st == "?":
+ unknown_files.append(fn)
+ return unknown_files
+
+ def GetBaseFile(self, filename):
+ # "hg status" and "hg cat" both take a path relative to the current subdir
+ # rather than to the repo root, but "hg diff" has given us the full path
+ # to the repo root.
+ base_content = ""
+ new_content = None
+ is_binary = False
+ oldrelpath = relpath = self._GetRelPath(filename)
+ # "hg status -C" returns two lines for moved/copied files, one otherwise
+ out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath])
+ out = out.splitlines()
+ # HACK: strip error message about missing file/directory if it isn't in
+ # the working copy
+ if out[0].startswith('%s: ' % relpath):
+ out = out[1:]
+ if len(out) > 1:
+ # Moved/copied => considered as modified, use old filename to
+ # retrieve base contents
+ oldrelpath = out[1].strip()
+ status = "M"
+ else:
+ status, _ = out[0].split(' ', 1)
+ if status != "A":
+ base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath],
+ silent_ok=True)
+ is_binary = "\0" in base_content # Mercurial's heuristic
+ if status != "R":
+ new_content = open(relpath, "rb").read()
+ is_binary = is_binary or "\0" in new_content
+ if is_binary and base_content:
+ # Fetch again without converting newlines
+ base_content = RunShell(["hg", "cat", "-r", self.base_rev, oldrelpath],
+ silent_ok=True, universal_newlines=False)
+ if not is_binary or not self.IsImage(relpath):
+ new_content = None
+ return base_content, new_content, is_binary, status
+
+
+# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync.
+def SplitPatch(data):
+ """Splits a patch into separate pieces for each file.
+
+ Args:
+ data: A string containing the output of svn diff.
+
+ Returns:
+ A list of 2-tuple (filename, text) where text is the svn diff output
+ pertaining to filename.
+ """
+ patches = []
+ filename = None
+ diff = []
+ for line in data.splitlines(True):
+ new_filename = None
+ if line.startswith('Index:'):
+ unused, new_filename = line.split(':', 1)
+ new_filename = new_filename.strip()
+ elif line.startswith('Property changes on:'):
+ unused, temp_filename = line.split(':', 1)
+ # When a file is modified, paths use '/' between directories, however
+ # when a property is modified '\' is used on Windows. Make them the same
+ # otherwise the file shows up twice.
+ temp_filename = temp_filename.strip().replace('\\', '/')
+ if temp_filename != filename:
+ # File has property changes but no modifications, create a new diff.
+ new_filename = temp_filename
+ if new_filename:
+ if filename and diff:
+ patches.append((filename, ''.join(diff)))
+ filename = new_filename
+ diff = [line]
+ continue
+ if diff is not None:
+ diff.append(line)
+ if filename and diff:
+ patches.append((filename, ''.join(diff)))
+ return patches
+
+
+def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
+ """Uploads a separate patch for each file in the diff output.
+
+ Returns a list of [patch_key, filename] for each file.
+ """
+ patches = SplitPatch(data)
+ rv = []
+ for patch in patches:
+ if len(patch[1]) > MAX_UPLOAD_SIZE:
+ print ("Not uploading the patch for " + patch[0] +
+ " because the file is too large.")
+ continue
+ form_fields = [("filename", patch[0])]
+ if not options.download_base:
+ form_fields.append(("content_upload", "1"))
+ files = [("data", "data.diff", patch[1])]
+ ctype, body = EncodeMultipartFormData(form_fields, files)
+ url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
+ print "Uploading patch for " + patch[0]
+ response_body = rpc_server.Send(url, body, content_type=ctype)
+ lines = response_body.splitlines()
+ if not lines or lines[0] != "OK":
+ StatusUpdate(" --> %s" % response_body)
+ sys.exit(1)
+ rv.append([lines[1], patch[0]])
+ return rv
+
+
+def GuessVCS(options):
+ """Helper to guess the version control system.
+
+ This examines the current directory, guesses which VersionControlSystem
+ we're using, and returns an instance of the appropriate class. Exit with an
+ error if we can't figure it out.
+
+ Returns:
+ A VersionControlSystem instance. Exits if the VCS can't be guessed.
+ """
+ # Mercurial has a command to get the base directory of a repository
+ # Try running it, but don't die if we don't have hg installed.
+ # NOTE: we try Mercurial first as it can sit on top of an SVN working copy.
+ try:
+ out, returncode = RunShellWithReturnCode(["hg", "root"])
+ if returncode == 0:
+ return MercurialVCS(options, out.strip())
+ except OSError, (errno, message):
+ if errno != 2: # ENOENT -- they don't have hg installed.
+ raise
+
+ # Subversion has a .svn in all working directories.
+ if os.path.isdir('.svn'):
+ logging.info("Guessed VCS = Subversion")
+ return SubversionVCS(options)
+
+ # Git has a command to test if you're in a git tree.
+ # Try running it, but don't die if we don't have git installed.
+ try:
+ out, returncode = RunShellWithReturnCode(["git", "rev-parse",
+ "--is-inside-work-tree"])
+ if returncode == 0:
+ return GitVCS(options)
+ except OSError, (errno, message):
+ if errno != 2: # ENOENT -- they don't have git installed.
+ raise
+
+ ErrorExit(("Could not guess version control system. "
+ "Are you in a working copy directory?"))
+
+
+def RealMain(argv, data=None):
+ """The real main function.
+
+ Args:
+ argv: Command line arguments.
+ data: Diff contents. If None (default) the diff is generated by
+ the VersionControlSystem implementation returned by GuessVCS().
+
+ Returns:
+ A 2-tuple (issue id, patchset id).
+ The patchset id is None if the base files are not uploaded by this
+ script (applies only to SVN checkouts).
+ """
+ logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:"
+ "%(lineno)s %(message)s "))
+ os.environ['LC_ALL'] = 'C'
+ options, args = parser.parse_args(argv[1:])
+ global verbosity
+ verbosity = options.verbose
+ if verbosity >= 3:
+ logging.getLogger().setLevel(logging.DEBUG)
+ elif verbosity >= 2:
+ logging.getLogger().setLevel(logging.INFO)
+ vcs = GuessVCS(options)
+ if isinstance(vcs, SubversionVCS):
+ # base field is only allowed for Subversion.
+ # Note: Fetching base files may become deprecated in future releases.
+ base = vcs.GuessBase(options.download_base)
+ else:
+ base = None
+ if not base and options.download_base:
+ options.download_base = True
+ logging.info("Enabled upload of base file")
+ if not options.assume_yes:
+ vcs.CheckForUnknownFiles()
+ if data is None:
+ data = vcs.GenerateDiff(args)
+ files = vcs.GetBaseFiles(data)
+ if verbosity >= 1:
+ print "Upload server:", options.server, "(change with -s/--server)"
+ if options.issue:
+ prompt = "Message describing this patch set: "
+ else:
+ prompt = "New issue subject: "
+ message = options.message or raw_input(prompt).strip()
+ if not message:
+ ErrorExit("A non-empty message is required")
+ rpc_server = GetRpcServer(options)
+ form_fields = [("subject", message)]
+ if base:
+ form_fields.append(("base", base))
+ if options.issue:
+ form_fields.append(("issue", str(options.issue)))
+ if options.email:
+ form_fields.append(("user", options.email))
+ if options.reviewers:
+ for reviewer in options.reviewers.split(','):
+ if "@" in reviewer and not reviewer.split("@")[1].count(".") == 1:
+ ErrorExit("Invalid email address: %s" % reviewer)
+ form_fields.append(("reviewers", options.reviewers))
+ if options.cc:
+ for cc in options.cc.split(','):
+ if "@" in cc and not cc.split("@")[1].count(".") == 1:
+ ErrorExit("Invalid email address: %s" % cc)
+ form_fields.append(("cc", options.cc))
+ description = options.description
+ if options.description_file:
+ if options.description:
+ ErrorExit("Can't specify description and description_file")
+ file = open(options.description_file, 'r')
+ description = file.read()
+ file.close()
+ if description:
+ form_fields.append(("description", description))
+ # Send a hash of all the base file so the server can determine if a copy
+ # already exists in an earlier patchset.
+ base_hashes = ""
+ for file, info in files.iteritems():
+ if not info[0] is None:
+ checksum = md5.new(info[0]).hexdigest()
+ if base_hashes:
+ base_hashes += "|"
+ base_hashes += checksum + ":" + file
+ form_fields.append(("base_hashes", base_hashes))
+ # If we're uploading base files, don't send the email before the uploads, so
+ # that it contains the file status.
+ if options.send_mail and options.download_base:
+ form_fields.append(("send_mail", "1"))
+ if not options.download_base:
+ form_fields.append(("content_upload", "1"))
+ if len(data) > MAX_UPLOAD_SIZE:
+ print "Patch is large, so uploading file patches separately."
+ uploaded_diff_file = []
+ form_fields.append(("separate_patches", "1"))
+ else:
+ uploaded_diff_file = [("data", "data.diff", data)]
+ ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
+ response_body = rpc_server.Send("/upload", body, content_type=ctype)
+ patchset = None
+ if not options.download_base or not uploaded_diff_file:
+ lines = response_body.splitlines()
+ if len(lines) >= 2:
+ msg = lines[0]
+ patchset = lines[1].strip()
+ patches = [x.split(" ", 1) for x in lines[2:]]
+ else:
+ msg = response_body
+ else:
+ msg = response_body
+ StatusUpdate(msg)
+ if not response_body.startswith("Issue created.") and \
+ not response_body.startswith("Issue updated."):
+ sys.exit(0)
+ issue = msg[msg.rfind("/")+1:]
+
+ if not uploaded_diff_file:
+ result = UploadSeparatePatches(issue, rpc_server, patchset, data, options)
+ if not options.download_base:
+ patches = result
+
+ if not options.download_base:
+ vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files)
+ if options.send_mail:
+ rpc_server.Send("/" + issue + "/mail", payload="")
+ return issue, patchset
+
+
+def main():
+ try:
+ RealMain(sys.argv)
+ except KeyboardInterrupt:
+ print
+ StatusUpdate("Interrupted.")
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Source/ThirdParty/gtest/scripts/upload_gtest.py b/Source/ThirdParty/gtest/scripts/upload_gtest.py
new file mode 100755
index 000000000..be19ae809
--- /dev/null
+++ b/Source/ThirdParty/gtest/scripts/upload_gtest.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""upload_gtest.py v0.1.0 -- uploads a Google Test patch for review.
+
+This simple wrapper passes all command line flags and
+--cc=googletestframework@googlegroups.com to upload.py.
+
+USAGE: upload_gtest.py [options for upload.py]
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import sys
+
+CC_FLAG = '--cc='
+GTEST_GROUP = 'googletestframework@googlegroups.com'
+
+
+def main():
+ # Finds the path to upload.py, assuming it is in the same directory
+ # as this file.
+ my_dir = os.path.dirname(os.path.abspath(__file__))
+ upload_py_path = os.path.join(my_dir, 'upload.py')
+
+ # Adds Google Test discussion group to the cc line if it's not there
+ # already.
+ upload_py_argv = [upload_py_path]
+ found_cc_flag = False
+ for arg in sys.argv[1:]:
+ if arg.startswith(CC_FLAG):
+ found_cc_flag = True
+ cc_line = arg[len(CC_FLAG):]
+ cc_list = [addr for addr in cc_line.split(',') if addr]
+ if GTEST_GROUP not in cc_list:
+ cc_list.append(GTEST_GROUP)
+ upload_py_argv.append(CC_FLAG + ','.join(cc_list))
+ else:
+ upload_py_argv.append(arg)
+
+ if not found_cc_flag:
+ upload_py_argv.append(CC_FLAG + GTEST_GROUP)
+
+ # Invokes upload.py with the modified command line flags.
+ os.execv(upload_py_path, upload_py_argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/Source/ThirdParty/gtest/src/gtest-all.cc b/Source/ThirdParty/gtest/src/gtest-all.cc
new file mode 100644
index 000000000..fe34765fb
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest-all.cc
@@ -0,0 +1,47 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// Google C++ Testing Framework (Google Test)
+//
+// Sometimes it's desirable to build Google Test by compiling a single file.
+// This file serves this purpose.
+
+// This line ensures that gtest.h can be compiled on its own, even
+// when it's fused.
+#include <gtest/gtest.h>
+
+// The following lines pull in the real gtest *.cc files.
+#include "src/gtest.cc"
+#include "src/gtest-death-test.cc"
+#include "src/gtest-filepath.cc"
+#include "src/gtest-port.cc"
+#include "src/gtest-test-part.cc"
+#include "src/gtest-typed-test.cc"
diff --git a/Source/ThirdParty/gtest/src/gtest-death-test.cc b/Source/ThirdParty/gtest/src/gtest-death-test.cc
new file mode 100644
index 000000000..3b73b01d2
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest-death-test.cc
@@ -0,0 +1,1172 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
+//
+// This file implements death tests.
+
+#include <gtest/gtest-death-test.h>
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_MAC
+#include <crt_externs.h>
+#endif // GTEST_OS_MAC
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+
+#if GTEST_OS_WINDOWS
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#include <sys/wait.h>
+#endif // GTEST_OS_WINDOWS
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#include <gtest/gtest-message.h>
+#include <gtest/internal/gtest-string.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+// Constants.
+
+// The default death test style.
+static const char kDefaultDeathTestStyle[] = "fast";
+
+GTEST_DEFINE_string_(
+ death_test_style,
+ internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
+ "Indicates how to run a death test in a forked child process: "
+ "\"threadsafe\" (child process re-executes the test binary "
+ "from the beginning, running only the specific death test) or "
+ "\"fast\" (child process runs the death test immediately "
+ "after forking).");
+
+GTEST_DEFINE_bool_(
+ death_test_use_fork,
+ internal::BoolFromGTestEnv("death_test_use_fork", false),
+ "Instructs to use fork()/_exit() instead of clone() in death tests. "
+ "Ignored and always uses fork() on POSIX systems where clone() is not "
+ "implemented. Useful when running under valgrind or similar tools if "
+ "those do not support clone(). Valgrind 3.3.1 will just fail if "
+ "it sees an unsupported combination of clone() flags. "
+ "It is not recommended to use this flag w/o valgrind though it will "
+ "work in 99% of the cases. Once valgrind is fixed, this flag will "
+ "most likely be removed.");
+
+namespace internal {
+GTEST_DEFINE_string_(
+ internal_run_death_test, "",
+ "Indicates the file, line number, temporal index of "
+ "the single death test to run, and a file descriptor to "
+ "which a success code may be sent, all separated by "
+ "colons. This flag is specified if and only if the current "
+ "process is a sub-process launched for running a thread-safe "
+ "death test. FOR INTERNAL USE ONLY.");
+} // namespace internal
+
+#if GTEST_HAS_DEATH_TEST
+
+// ExitedWithCode constructor.
+ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
+}
+
+// ExitedWithCode function-call operator.
+bool ExitedWithCode::operator()(int exit_status) const {
+#if GTEST_OS_WINDOWS
+ return exit_status == exit_code_;
+#else
+ return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
+#endif // GTEST_OS_WINDOWS
+}
+
+#if !GTEST_OS_WINDOWS
+// KilledBySignal constructor.
+KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
+}
+
+// KilledBySignal function-call operator.
+bool KilledBySignal::operator()(int exit_status) const {
+ return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
+}
+#endif // !GTEST_OS_WINDOWS
+
+namespace internal {
+
+// Utilities needed for death tests.
+
+// Generates a textual description of a given exit code, in the format
+// specified by wait(2).
+static String ExitSummary(int exit_code) {
+ Message m;
+#if GTEST_OS_WINDOWS
+ m << "Exited with exit status " << exit_code;
+#else
+ if (WIFEXITED(exit_code)) {
+ m << "Exited with exit status " << WEXITSTATUS(exit_code);
+ } else if (WIFSIGNALED(exit_code)) {
+ m << "Terminated by signal " << WTERMSIG(exit_code);
+ }
+#ifdef WCOREDUMP
+ if (WCOREDUMP(exit_code)) {
+ m << " (core dumped)";
+ }
+#endif
+#endif // GTEST_OS_WINDOWS
+ return m.GetString();
+}
+
+// Returns true if exit_status describes a process that was terminated
+// by a signal, or exited normally with a nonzero exit code.
+bool ExitedUnsuccessfully(int exit_status) {
+ return !ExitedWithCode(0)(exit_status);
+}
+
+#if !GTEST_OS_WINDOWS
+// Generates a textual failure message when a death test finds more than
+// one thread running, or cannot determine the number of threads, prior
+// to executing the given statement. It is the responsibility of the
+// caller not to pass a thread_count of 1.
+static String DeathTestThreadWarning(size_t thread_count) {
+ Message msg;
+ msg << "Death tests use fork(), which is unsafe particularly"
+ << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
+ if (thread_count == 0)
+ msg << "couldn't detect the number of threads.";
+ else
+ msg << "detected " << thread_count << " threads.";
+ return msg.GetString();
+}
+#endif // !GTEST_OS_WINDOWS
+
+// Flag characters for reporting a death test that did not die.
+static const char kDeathTestLived = 'L';
+static const char kDeathTestReturned = 'R';
+static const char kDeathTestInternalError = 'I';
+
+// An enumeration describing all of the possible ways that a death test
+// can conclude. DIED means that the process died while executing the
+// test code; LIVED means that process lived beyond the end of the test
+// code; and RETURNED means that the test statement attempted a "return,"
+// which is not allowed. IN_PROGRESS means the test has not yet
+// concluded.
+enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };
+
+// Routine for aborting the program which is safe to call from an
+// exec-style death test child process, in which case the error
+// message is propagated back to the parent process. Otherwise, the
+// message is simply printed to stderr. In either case, the program
+// then exits with status 1.
+void DeathTestAbort(const String& message) {
+ // On a POSIX system, this function may be called from a threadsafe-style
+ // death test child process, which operates on a very small stack. Use
+ // the heap for any additional non-minuscule memory requirements.
+ const InternalRunDeathTestFlag* const flag =
+ GetUnitTestImpl()->internal_run_death_test_flag();
+ if (flag != NULL) {
+ FILE* parent = posix::FDOpen(flag->write_fd(), "w");
+ fputc(kDeathTestInternalError, parent);
+ fprintf(parent, "%s", message.c_str());
+ fflush(parent);
+ _exit(1);
+ } else {
+ fprintf(stderr, "%s", message.c_str());
+ fflush(stderr);
+ abort();
+ }
+}
+
+// A replacement for CHECK that calls DeathTestAbort if the assertion
+// fails.
+#define GTEST_DEATH_TEST_CHECK_(expression) \
+ do { \
+ if (!::testing::internal::IsTrue(expression)) { \
+ DeathTestAbort(::testing::internal::String::Format( \
+ "CHECK failed: File %s, line %d: %s", \
+ __FILE__, __LINE__, #expression)); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
+// evaluating any system call that fulfills two conditions: it must return
+// -1 on failure, and set errno to EINTR when it is interrupted and
+// should be tried again. The macro expands to a loop that repeatedly
+// evaluates the expression as long as it evaluates to -1 and sets
+// errno to EINTR. If the expression evaluates to -1 but errno is
+// something other than EINTR, DeathTestAbort is called.
+#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
+ do { \
+ int gtest_retval; \
+ do { \
+ gtest_retval = (expression); \
+ } while (gtest_retval == -1 && errno == EINTR); \
+ if (gtest_retval == -1) { \
+ DeathTestAbort(::testing::internal::String::Format( \
+ "CHECK failed: File %s, line %d: %s != -1", \
+ __FILE__, __LINE__, #expression)); \
+ } \
+ } while (::testing::internal::AlwaysFalse())
+
+// Returns the message describing the last system error in errno.
+String GetLastErrnoDescription() {
+ return String(errno == 0 ? "" : posix::StrError(errno));
+}
+
+// This is called from a death test parent process to read a failure
+// message from the death test child process and log it with the FATAL
+// severity. On Windows, the message is read from a pipe handle. On other
+// platforms, it is read from a file descriptor.
+static void FailFromInternalError(int fd) {
+ Message error;
+ char buffer[256];
+ int num_read;
+
+ do {
+ while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
+ buffer[num_read] = '\0';
+ error << buffer;
+ }
+ } while (num_read == -1 && errno == EINTR);
+
+ if (num_read == 0) {
+ GTEST_LOG_(FATAL) << error.GetString();
+ } else {
+ const int last_error = errno;
+ GTEST_LOG_(FATAL) << "Error while reading death test internal: "
+ << GetLastErrnoDescription() << " [" << last_error << "]";
+ }
+}
+
+// Death test constructor. Increments the running death test count
+// for the current test.
+DeathTest::DeathTest() {
+ TestInfo* const info = GetUnitTestImpl()->current_test_info();
+ if (info == NULL) {
+ DeathTestAbort("Cannot run a death test outside of a TEST or "
+ "TEST_F construct");
+ }
+}
+
+// Creates and returns a death test by dispatching to the current
+// death test factory.
+bool DeathTest::Create(const char* statement, const RE* regex,
+ const char* file, int line, DeathTest** test) {
+ return GetUnitTestImpl()->death_test_factory()->Create(
+ statement, regex, file, line, test);
+}
+
+const char* DeathTest::LastMessage() {
+ return last_death_test_message_.c_str();
+}
+
+void DeathTest::set_last_death_test_message(const String& message) {
+ last_death_test_message_ = message;
+}
+
+String DeathTest::last_death_test_message_;
+
+// Provides cross platform implementation for some death functionality.
+class DeathTestImpl : public DeathTest {
+ protected:
+ DeathTestImpl(const char* a_statement, const RE* a_regex)
+ : statement_(a_statement),
+ regex_(a_regex),
+ spawned_(false),
+ status_(-1),
+ outcome_(IN_PROGRESS),
+ read_fd_(-1),
+ write_fd_(-1) {}
+
+ // read_fd_ is expected to be closed and cleared by a derived class.
+ ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
+
+ void Abort(AbortReason reason);
+ virtual bool Passed(bool status_ok);
+
+ const char* statement() const { return statement_; }
+ const RE* regex() const { return regex_; }
+ bool spawned() const { return spawned_; }
+ void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
+ int status() const { return status_; }
+ void set_status(int a_status) { status_ = a_status; }
+ DeathTestOutcome outcome() const { return outcome_; }
+ void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
+ int read_fd() const { return read_fd_; }
+ void set_read_fd(int fd) { read_fd_ = fd; }
+ int write_fd() const { return write_fd_; }
+ void set_write_fd(int fd) { write_fd_ = fd; }
+
+ // Called in the parent process only. Reads the result code of the death
+ // test child process via a pipe, interprets it to set the outcome_
+ // member, and closes read_fd_. Outputs diagnostics and terminates in
+ // case of unexpected codes.
+ void ReadAndInterpretStatusByte();
+
+ private:
+ // The textual content of the code this object is testing. This class
+ // doesn't own this string and should not attempt to delete it.
+ const char* const statement_;
+ // The regular expression which test output must match. DeathTestImpl
+ // doesn't own this object and should not attempt to delete it.
+ const RE* const regex_;
+ // True if the death test child process has been successfully spawned.
+ bool spawned_;
+ // The exit status of the child process.
+ int status_;
+ // How the death test concluded.
+ DeathTestOutcome outcome_;
+ // Descriptor to the read end of the pipe to the child process. It is
+ // always -1 in the child process. The child keeps its write end of the
+ // pipe in write_fd_.
+ int read_fd_;
+ // Descriptor to the child's write end of the pipe to the parent process.
+ // It is always -1 in the parent process. The parent keeps its end of the
+ // pipe in read_fd_.
+ int write_fd_;
+};
+
+// Called in the parent process only. Reads the result code of the death
+// test child process via a pipe, interprets it to set the outcome_
+// member, and closes read_fd_. Outputs diagnostics and terminates in
+// case of unexpected codes.
+void DeathTestImpl::ReadAndInterpretStatusByte() {
+ char flag;
+ int bytes_read;
+
+ // The read() here blocks until data is available (signifying the
+ // failure of the death test) or until the pipe is closed (signifying
+ // its success), so it's okay to call this in the parent before
+ // the child process has exited.
+ do {
+ bytes_read = posix::Read(read_fd(), &flag, 1);
+ } while (bytes_read == -1 && errno == EINTR);
+
+ if (bytes_read == 0) {
+ set_outcome(DIED);
+ } else if (bytes_read == 1) {
+ switch (flag) {
+ case kDeathTestReturned:
+ set_outcome(RETURNED);
+ break;
+ case kDeathTestLived:
+ set_outcome(LIVED);
+ break;
+ case kDeathTestInternalError:
+ FailFromInternalError(read_fd()); // Does not return.
+ break;
+ default:
+ GTEST_LOG_(FATAL) << "Death test child process reported "
+ << "unexpected status byte ("
+ << static_cast<unsigned int>(flag) << ")";
+ }
+ } else {
+ GTEST_LOG_(FATAL) << "Read from death test child process failed: "
+ << GetLastErrnoDescription();
+ }
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
+ set_read_fd(-1);
+}
+
+// Signals that the death test code which should have exited, didn't.
+// Should be called only in a death test child process.
+// Writes a status byte to the child's status file descriptor, then
+// calls _exit(1).
+void DeathTestImpl::Abort(AbortReason reason) {
+ // The parent process considers the death test to be a failure if
+ // it finds any data in our pipe. So, here we write a single flag byte
+ // to the pipe, then exit.
+ const char status_ch =
+ reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd()));
+ _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
+}
+
+// Assesses the success or failure of a death test, using both private
+// members which have previously been set, and one argument:
+//
+// Private data members:
+// outcome: An enumeration describing how the death test
+// concluded: DIED, LIVED, or RETURNED. The death test fails
+// in the latter two cases.
+// status: The exit status of the child process. On *nix, it is in the
+// in the format specified by wait(2). On Windows, this is the
+// value supplied to the ExitProcess() API or a numeric code
+// of the exception that terminated the program.
+// regex: A regular expression object to be applied to
+// the test's captured standard error output; the death test
+// fails if it does not match.
+//
+// Argument:
+// status_ok: true if exit_status is acceptable in the context of
+// this particular death test, which fails if it is false
+//
+// Returns true iff all of the above conditions are met. Otherwise, the
+// first failing condition, in the order given above, is the one that is
+// reported. Also sets the last death test message string.
+bool DeathTestImpl::Passed(bool status_ok) {
+ if (!spawned())
+ return false;
+
+ const String error_message = GetCapturedStderr();
+
+ bool success = false;
+ Message buffer;
+
+ buffer << "Death test: " << statement() << "\n";
+ switch (outcome()) {
+ case LIVED:
+ buffer << " Result: failed to die.\n"
+ << " Error msg: " << error_message;
+ break;
+ case RETURNED:
+ buffer << " Result: illegal return in test statement.\n"
+ << " Error msg: " << error_message;
+ break;
+ case DIED:
+ if (status_ok) {
+ const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
+ if (matched) {
+ success = true;
+ } else {
+ buffer << " Result: died but not with expected error.\n"
+ << " Expected: " << regex()->pattern() << "\n"
+ << "Actual msg: " << error_message;
+ }
+ } else {
+ buffer << " Result: died but not with expected exit code:\n"
+ << " " << ExitSummary(status()) << "\n";
+ }
+ break;
+ case IN_PROGRESS:
+ default:
+ GTEST_LOG_(FATAL)
+ << "DeathTest::Passed somehow called before conclusion of test";
+ }
+
+ DeathTest::set_last_death_test_message(buffer.GetString());
+ return success;
+}
+
+#if GTEST_OS_WINDOWS
+// WindowsDeathTest implements death tests on Windows. Due to the
+// specifics of starting new processes on Windows, death tests there are
+// always threadsafe, and Google Test considers the
+// --gtest_death_test_style=fast setting to be equivalent to
+// --gtest_death_test_style=threadsafe there.
+//
+// A few implementation notes: Like the Linux version, the Windows
+// implementation uses pipes for child-to-parent communication. But due to
+// the specifics of pipes on Windows, some extra steps are required:
+//
+// 1. The parent creates a communication pipe and stores handles to both
+// ends of it.
+// 2. The parent starts the child and provides it with the information
+// necessary to acquire the handle to the write end of the pipe.
+// 3. The child acquires the write end of the pipe and signals the parent
+// using a Windows event.
+// 4. Now the parent can release the write end of the pipe on its side. If
+// this is done before step 3, the object's reference count goes down to
+// 0 and it is destroyed, preventing the child from acquiring it. The
+// parent now has to release it, or read operations on the read end of
+// the pipe will not return when the child terminates.
+// 5. The parent reads child's output through the pipe (outcome code and
+// any possible error messages) from the pipe, and its stderr and then
+// determines whether to fail the test.
+//
+// Note: to distinguish Win32 API calls from the local method and function
+// calls, the former are explicitly resolved in the global namespace.
+//
+class WindowsDeathTest : public DeathTestImpl {
+ public:
+ WindowsDeathTest(const char* statement,
+ const RE* regex,
+ const char* file,
+ int line)
+ : DeathTestImpl(statement, regex), file_(file), line_(line) {}
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+ virtual TestRole AssumeRole();
+
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+ // Handle to the write end of the pipe to the child process.
+ AutoHandle write_handle_;
+ // Child process handle.
+ AutoHandle child_handle_;
+ // Event the child process uses to signal the parent that it has
+ // acquired the handle to the write end of the pipe. After seeing this
+ // event the parent can release its own handles to make sure its
+ // ReadFile() calls return when the child terminates.
+ AutoHandle event_handle_;
+};
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int WindowsDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ // Wait until the child either signals that it has acquired the write end
+ // of the pipe or it dies.
+ const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
+ switch (::WaitForMultipleObjects(2,
+ wait_handles,
+ FALSE, // Waits for any of the handles.
+ INFINITE)) {
+ case WAIT_OBJECT_0:
+ case WAIT_OBJECT_0 + 1:
+ break;
+ default:
+ GTEST_DEATH_TEST_CHECK_(false); // Should not get here.
+ }
+
+ // The child has acquired the write end of the pipe or exited.
+ // We release the handle on our side and continue.
+ write_handle_.Reset();
+ event_handle_.Reset();
+
+ ReadAndInterpretStatusByte();
+
+ // Waits for the child process to exit if it haven't already. This
+ // returns immediately if the child has already exited, regardless of
+ // whether previous calls to WaitForMultipleObjects synchronized on this
+ // handle or not.
+ GTEST_DEATH_TEST_CHECK_(
+ WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
+ INFINITE));
+ DWORD status;
+ GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status)
+ != FALSE);
+ child_handle_.Reset();
+ set_status(static_cast<int>(status));
+ return this->status();
+}
+
+// The AssumeRole process for a Windows death test. It creates a child
+// process with the same executable as the current process to run the
+// death test. The child process is given the --gtest_filter and
+// --gtest_internal_run_death_test flags such that it knows to run the
+// current death test only.
+DeathTest::TestRole WindowsDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ // ParseInternalRunDeathTestFlag() has performed all the necessary
+ // processing.
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ // WindowsDeathTest uses an anonymous pipe to communicate results of
+ // a death test.
+ SECURITY_ATTRIBUTES handles_are_inheritable = {
+ sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+ HANDLE read_handle, write_handle;
+ GTEST_DEATH_TEST_CHECK_(
+ ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
+ 0) // Default buffer size.
+ != FALSE);
+ set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
+ O_RDONLY));
+ write_handle_.Reset(write_handle);
+ event_handle_.Reset(::CreateEvent(
+ &handles_are_inheritable,
+ TRUE, // The event will automatically reset to non-signaled state.
+ FALSE, // The initial state is non-signalled.
+ NULL)); // The even is unnamed.
+ GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
+ const String filter_flag = String::Format("--%s%s=%s.%s",
+ GTEST_FLAG_PREFIX_, kFilterFlag,
+ info->test_case_name(),
+ info->name());
+ const String internal_flag = String::Format(
+ "--%s%s=%s|%d|%d|%u|%Iu|%Iu",
+ GTEST_FLAG_PREFIX_,
+ kInternalRunDeathTestFlag,
+ file_, line_,
+ death_test_index,
+ static_cast<unsigned int>(::GetCurrentProcessId()),
+ // size_t has the same with as pointers on both 32-bit and 64-bit
+ // Windows platforms.
+ // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
+ reinterpret_cast<size_t>(write_handle),
+ reinterpret_cast<size_t>(event_handle_.Get()));
+
+ char executable_path[_MAX_PATH + 1]; // NOLINT
+ GTEST_DEATH_TEST_CHECK_(
+ _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
+ executable_path,
+ _MAX_PATH));
+
+ String command_line = String::Format("%s %s \"%s\"",
+ ::GetCommandLineA(),
+ filter_flag.c_str(),
+ internal_flag.c_str());
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // Flush the log buffers since the log streams are shared with the child.
+ FlushInfoLog();
+
+ // The child process will share the standard handles with the parent.
+ STARTUPINFOA startup_info;
+ memset(&startup_info, 0, sizeof(STARTUPINFO));
+ startup_info.dwFlags = STARTF_USESTDHANDLES;
+ startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+ startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
+
+ PROCESS_INFORMATION process_info;
+ GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
+ executable_path,
+ const_cast<char*>(command_line.c_str()),
+ NULL, // Retuned process handle is not inheritable.
+ NULL, // Retuned thread handle is not inheritable.
+ TRUE, // Child inherits all inheritable handles (for write_handle_).
+ 0x0, // Default creation flags.
+ NULL, // Inherit the parent's environment.
+ UnitTest::GetInstance()->original_working_dir(),
+ &startup_info,
+ &process_info) != FALSE);
+ child_handle_.Reset(process_info.hProcess);
+ ::CloseHandle(process_info.hThread);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+#else // We are not on Windows.
+
+// ForkingDeathTest provides implementations for most of the abstract
+// methods of the DeathTest interface. Only the AssumeRole method is
+// left undefined.
+class ForkingDeathTest : public DeathTestImpl {
+ public:
+ ForkingDeathTest(const char* statement, const RE* regex);
+
+ // All of these virtual functions are inherited from DeathTest.
+ virtual int Wait();
+
+ protected:
+ void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
+
+ private:
+ // PID of child process during death test; 0 in the child process itself.
+ pid_t child_pid_;
+};
+
+// Constructs a ForkingDeathTest.
+ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
+ : DeathTestImpl(a_statement, a_regex),
+ child_pid_(-1) {}
+
+// Waits for the child in a death test to exit, returning its exit
+// status, or 0 if no child process exists. As a side effect, sets the
+// outcome data member.
+int ForkingDeathTest::Wait() {
+ if (!spawned())
+ return 0;
+
+ ReadAndInterpretStatusByte();
+
+ int status_value;
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
+ set_status(status_value);
+ return status_value;
+}
+
+// A concrete death test class that forks, then immediately runs the test
+// in the child process.
+class NoExecDeathTest : public ForkingDeathTest {
+ public:
+ NoExecDeathTest(const char* a_statement, const RE* a_regex) :
+ ForkingDeathTest(a_statement, a_regex) { }
+ virtual TestRole AssumeRole();
+};
+
+// The AssumeRole process for a fork-and-run death test. It implements a
+// straightforward fork, with a simple pipe to transmit the status byte.
+DeathTest::TestRole NoExecDeathTest::AssumeRole() {
+ const size_t thread_count = GetThreadCount();
+ if (thread_count != 1) {
+ GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+
+ DeathTest::set_last_death_test_message("");
+ CaptureStderr();
+ // When we fork the process below, the log file buffers are copied, but the
+ // file descriptors are shared. We flush all log files here so that closing
+ // the file descriptors in the child process doesn't throw off the
+ // synchronization between descriptors and buffers in the parent process.
+ // This is as close to the fork as possible to avoid a race condition in case
+ // there are multiple threads running before the death test, and another
+ // thread writes to the log file.
+ FlushInfoLog();
+
+ const pid_t child_pid = fork();
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ set_child_pid(child_pid);
+ if (child_pid == 0) {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
+ set_write_fd(pipe_fd[1]);
+ // Redirects all logging to stderr in the child process to prevent
+ // concurrent writes to the log files. We capture stderr in the parent
+ // process and append the child process' output to a log.
+ LogToStderr();
+ // Event forwarding to the listeners of event listener API mush be shut
+ // down in death test subprocesses.
+ GetUnitTestImpl()->listeners()->SuppressEventForwarding();
+ return EXECUTE_TEST;
+ } else {
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_read_fd(pipe_fd[0]);
+ set_spawned(true);
+ return OVERSEE_TEST;
+ }
+}
+
+// A concrete death test class that forks and re-executes the main
+// program from the beginning, with command-line flags set that cause
+// only this specific death test to be run.
+class ExecDeathTest : public ForkingDeathTest {
+ public:
+ ExecDeathTest(const char* a_statement, const RE* a_regex,
+ const char* file, int line) :
+ ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
+ virtual TestRole AssumeRole();
+ private:
+ // The name of the file in which the death test is located.
+ const char* const file_;
+ // The line number on which the death test is located.
+ const int line_;
+};
+
+// Utility class for accumulating command-line arguments.
+class Arguments {
+ public:
+ Arguments() {
+ args_.push_back(NULL);
+ }
+
+ ~Arguments() {
+ for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
+ ++i) {
+ free(*i);
+ }
+ }
+ void AddArgument(const char* argument) {
+ args_.insert(args_.end() - 1, posix::StrDup(argument));
+ }
+
+ template <typename Str>
+ void AddArguments(const ::std::vector<Str>& arguments) {
+ for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
+ i != arguments.end();
+ ++i) {
+ args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
+ }
+ }
+ char* const* Argv() {
+ return &args_[0];
+ }
+ private:
+ std::vector<char*> args_;
+};
+
+// A struct that encompasses the arguments to the child process of a
+// threadsafe-style death test process.
+struct ExecDeathTestArgs {
+ char* const* argv; // Command-line arguments for the child's call to exec
+ int close_fd; // File descriptor to close; the read end of a pipe
+};
+
+#if GTEST_OS_MAC
+inline char** GetEnviron() {
+ // When Google Test is built as a framework on MacOS X, the environ variable
+ // is unavailable. Apple's documentation (man environ) recommends using
+ // _NSGetEnviron() instead.
+ return *_NSGetEnviron();
+}
+#else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+#endif // GTEST_OS_MAC
+
+// The main function for a threadsafe-style death test child process.
+// This function is called in a clone()-ed process and thus must avoid
+// any potentially unsafe operations like malloc or libc functions.
+static int ExecDeathTestChildMain(void* child_arg) {
+ ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
+
+ // We need to execute the test program in the same environment where
+ // it was originally invoked. Therefore we change to the original
+ // working directory first.
+ const char* const original_dir =
+ UnitTest::GetInstance()->original_working_dir();
+ // We can safely call chdir() as it's a direct system call.
+ if (chdir(original_dir) != 0) {
+ DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
+ original_dir,
+ GetLastErrnoDescription().c_str()));
+ return EXIT_FAILURE;
+ }
+
+ // We can safely call execve() as it's a direct system call. We
+ // cannot use execvp() as it's a libc function and thus potentially
+ // unsafe. Since execve() doesn't search the PATH, the user must
+ // invoke the test program via a valid path that contains at least
+ // one path separator.
+ execve(args->argv[0], args->argv, GetEnviron());
+ DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s",
+ args->argv[0],
+ original_dir,
+ GetLastErrnoDescription().c_str()));
+ return EXIT_FAILURE;
+}
+
+// Two utility routines that together determine the direction the stack
+// grows.
+// This could be accomplished more elegantly by a single recursive
+// function, but we want to guard against the unlikely possibility of
+// a smart compiler optimizing the recursion away.
+bool StackLowerThanAddress(const void* ptr) {
+ int dummy;
+ return &dummy < ptr;
+}
+
+bool StackGrowsDown() {
+ int dummy;
+ return StackLowerThanAddress(&dummy);
+}
+
+// A threadsafe implementation of fork(2) for threadsafe-style death tests
+// that uses clone(2). It dies with an error message if anything goes
+// wrong.
+static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
+ ExecDeathTestArgs args = { argv, close_fd };
+ pid_t child_pid = -1;
+
+#if GTEST_HAS_CLONE
+ const bool use_fork = GTEST_FLAG(death_test_use_fork);
+
+ if (!use_fork) {
+ static const bool stack_grows_down = StackGrowsDown();
+ const size_t stack_size = getpagesize();
+ // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
+ void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
+ void* const stack_top =
+ static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
+
+ child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
+
+ GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
+ }
+#else
+ const bool use_fork = true;
+#endif // GTEST_HAS_CLONE
+
+ if (use_fork && (child_pid = fork()) == 0) {
+ ExecDeathTestChildMain(&args);
+ _exit(0);
+ }
+
+ GTEST_DEATH_TEST_CHECK_(child_pid != -1);
+ return child_pid;
+}
+
+// The AssumeRole process for a fork-and-exec death test. It re-executes the
+// main program from the beginning, setting the --gtest_filter
+// and --gtest_internal_run_death_test flags to cause only the current
+// death test to be re-run.
+DeathTest::TestRole ExecDeathTest::AssumeRole() {
+ const UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const TestInfo* const info = impl->current_test_info();
+ const int death_test_index = info->result()->death_test_count();
+
+ if (flag != NULL) {
+ set_write_fd(flag->write_fd());
+ return EXECUTE_TEST;
+ }
+
+ int pipe_fd[2];
+ GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
+ // Clear the close-on-exec flag on the write end of the pipe, lest
+ // it be closed when the child process does an exec:
+ GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
+
+ const String filter_flag =
+ String::Format("--%s%s=%s.%s",
+ GTEST_FLAG_PREFIX_, kFilterFlag,
+ info->test_case_name(), info->name());
+ const String internal_flag =
+ String::Format("--%s%s=%s|%d|%d|%d",
+ GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,
+ file_, line_, death_test_index, pipe_fd[1]);
+ Arguments args;
+ args.AddArguments(GetArgvs());
+ args.AddArgument(filter_flag.c_str());
+ args.AddArgument(internal_flag.c_str());
+
+ DeathTest::set_last_death_test_message("");
+
+ CaptureStderr();
+ // See the comment in NoExecDeathTest::AssumeRole for why the next line
+ // is necessary.
+ FlushInfoLog();
+
+ const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);
+ GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
+ set_child_pid(child_pid);
+ set_read_fd(pipe_fd[0]);
+ set_spawned(true);
+ return OVERSEE_TEST;
+}
+
+#endif // !GTEST_OS_WINDOWS
+
+// Creates a concrete DeathTest-derived class that depends on the
+// --gtest_death_test_style flag, and sets the pointer pointed to
+// by the "test" argument to its address. If the test should be
+// skipped, sets that pointer to NULL. Returns true, unless the
+// flag is set to an invalid value.
+bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
+ const char* file, int line,
+ DeathTest** test) {
+ UnitTestImpl* const impl = GetUnitTestImpl();
+ const InternalRunDeathTestFlag* const flag =
+ impl->internal_run_death_test_flag();
+ const int death_test_index = impl->current_test_info()
+ ->increment_death_test_count();
+
+ if (flag != NULL) {
+ if (death_test_index > flag->index()) {
+ DeathTest::set_last_death_test_message(String::Format(
+ "Death test count (%d) somehow exceeded expected maximum (%d)",
+ death_test_index, flag->index()));
+ return false;
+ }
+
+ if (!(flag->file() == file && flag->line() == line &&
+ flag->index() == death_test_index)) {
+ *test = NULL;
+ return true;
+ }
+ }
+
+#if GTEST_OS_WINDOWS
+ if (GTEST_FLAG(death_test_style) == "threadsafe" ||
+ GTEST_FLAG(death_test_style) == "fast") {
+ *test = new WindowsDeathTest(statement, regex, file, line);
+ }
+#else
+ if (GTEST_FLAG(death_test_style) == "threadsafe") {
+ *test = new ExecDeathTest(statement, regex, file, line);
+ } else if (GTEST_FLAG(death_test_style) == "fast") {
+ *test = new NoExecDeathTest(statement, regex);
+ }
+#endif // GTEST_OS_WINDOWS
+ else { // NOLINT - this is more readable than unbalanced brackets inside #if.
+ DeathTest::set_last_death_test_message(String::Format(
+ "Unknown death test style \"%s\" encountered",
+ GTEST_FLAG(death_test_style).c_str()));
+ return false;
+ }
+
+ return true;
+}
+
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
+// ::std::string, so we can use it here.
+static void SplitString(const ::std::string& str, char delimiter,
+ ::std::vector< ::std::string>* dest) {
+ ::std::vector< ::std::string> parsed;
+ ::std::string::size_type pos = 0;
+ while (::testing::internal::AlwaysTrue()) {
+ const ::std::string::size_type colon = str.find(delimiter, pos);
+ if (colon == ::std::string::npos) {
+ parsed.push_back(str.substr(pos));
+ break;
+ } else {
+ parsed.push_back(str.substr(pos, colon - pos));
+ pos = colon + 1;
+ }
+ }
+ dest->swap(parsed);
+}
+
+#if GTEST_OS_WINDOWS
+// Recreates the pipe and event handles from the provided parameters,
+// signals the event, and returns a file descriptor wrapped around the pipe
+// handle. This function is called in the child process only.
+int GetStatusFileDescriptor(unsigned int parent_process_id,
+ size_t write_handle_as_size_t,
+ size_t event_handle_as_size_t) {
+ AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
+ FALSE, // Non-inheritable.
+ parent_process_id));
+ if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
+ DeathTestAbort(String::Format("Unable to open parent process %u",
+ parent_process_id));
+ }
+
+ // TODO(vladl@google.com): Replace the following check with a
+ // compile-time assertion when available.
+ GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
+
+ const HANDLE write_handle =
+ reinterpret_cast<HANDLE>(write_handle_as_size_t);
+ HANDLE dup_write_handle;
+
+ // The newly initialized handle is accessible only in in the parent
+ // process. To obtain one accessible within the child, we need to use
+ // DuplicateHandle.
+ if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
+ ::GetCurrentProcess(), &dup_write_handle,
+ 0x0, // Requested privileges ignored since
+ // DUPLICATE_SAME_ACCESS is used.
+ FALSE, // Request non-inheritable handler.
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort(String::Format(
+ "Unable to duplicate the pipe handle %Iu from the parent process %u",
+ write_handle_as_size_t, parent_process_id));
+ }
+
+ const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
+ HANDLE dup_event_handle;
+
+ if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
+ ::GetCurrentProcess(), &dup_event_handle,
+ 0x0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)) {
+ DeathTestAbort(String::Format(
+ "Unable to duplicate the event handle %Iu from the parent process %u",
+ event_handle_as_size_t, parent_process_id));
+ }
+
+ const int write_fd =
+ ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
+ if (write_fd == -1) {
+ DeathTestAbort(String::Format(
+ "Unable to convert pipe handle %Iu to a file descriptor",
+ write_handle_as_size_t));
+ }
+
+ // Signals the parent that the write end of the pipe has been acquired
+ // so the parent can release its own write end.
+ ::SetEvent(dup_event_handle);
+
+ return write_fd;
+}
+#endif // GTEST_OS_WINDOWS
+
+// Returns a newly created InternalRunDeathTestFlag object with fields
+// initialized from the GTEST_FLAG(internal_run_death_test) flag if
+// the flag is specified; otherwise returns NULL.
+InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
+ if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
+
+ // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
+ // can use it here.
+ int line = -1;
+ int index = -1;
+ ::std::vector< ::std::string> fields;
+ SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
+ int write_fd = -1;
+
+#if GTEST_OS_WINDOWS
+ unsigned int parent_process_id = 0;
+ size_t write_handle_as_size_t = 0;
+ size_t event_handle_as_size_t = 0;
+
+ if (fields.size() != 6
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &parent_process_id)
+ || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
+ || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
+ DeathTestAbort(String::Format(
+ "Bad --gtest_internal_run_death_test flag: %s",
+ GTEST_FLAG(internal_run_death_test).c_str()));
+ }
+ write_fd = GetStatusFileDescriptor(parent_process_id,
+ write_handle_as_size_t,
+ event_handle_as_size_t);
+#else
+ if (fields.size() != 4
+ || !ParseNaturalNumber(fields[1], &line)
+ || !ParseNaturalNumber(fields[2], &index)
+ || !ParseNaturalNumber(fields[3], &write_fd)) {
+ DeathTestAbort(String::Format(
+ "Bad --gtest_internal_run_death_test flag: %s",
+ GTEST_FLAG(internal_run_death_test).c_str()));
+ }
+#endif // GTEST_OS_WINDOWS
+ return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
+}
+
+} // namespace internal
+
+#endif // GTEST_HAS_DEATH_TEST
+
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/src/gtest-filepath.cc b/Source/ThirdParty/gtest/src/gtest-filepath.cc
new file mode 100644
index 000000000..c1ef9188a
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest-filepath.cc
@@ -0,0 +1,380 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray@gmail.com (Keith Ray)
+
+#include <gtest/internal/gtest-filepath.h>
+#include <gtest/internal/gtest-port.h>
+
+#include <stdlib.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+#include <windows.h>
+#elif GTEST_OS_WINDOWS
+#include <direct.h>
+#include <io.h>
+#elif GTEST_OS_SYMBIAN
+// Symbian OpenC has PATH_MAX in sys/syslimits.h
+#include <sys/syslimits.h>
+#else
+#include <limits.h>
+#include <climits> // Some Linux distributions define PATH_MAX here.
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_WINDOWS
+#define GTEST_PATH_MAX_ _MAX_PATH
+#elif defined(PATH_MAX)
+#define GTEST_PATH_MAX_ PATH_MAX
+#elif defined(_XOPEN_PATH_MAX)
+#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
+#else
+#define GTEST_PATH_MAX_ _POSIX_PATH_MAX
+#endif // GTEST_OS_WINDOWS
+
+#include <gtest/internal/gtest-string.h>
+
+namespace testing {
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+// On Windows, '\\' is the standard path separator, but many tools and the
+// Windows API also accept '/' as an alternate path separator. Unless otherwise
+// noted, a file path can contain either kind of path separators, or a mixture
+// of them.
+const char kPathSeparator = '\\';
+const char kAlternatePathSeparator = '/';
+const char kPathSeparatorString[] = "\\";
+const char kAlternatePathSeparatorString[] = "/";
+#if GTEST_OS_WINDOWS_MOBILE
+// Windows CE doesn't have a current directory. You should not use
+// the current directory in tests on Windows CE, but this at least
+// provides a reasonable fallback.
+const char kCurrentDirectoryString[] = "\\";
+// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
+const DWORD kInvalidFileAttributes = 0xffffffff;
+#else
+const char kCurrentDirectoryString[] = ".\\";
+#endif // GTEST_OS_WINDOWS_MOBILE
+#else
+const char kPathSeparator = '/';
+const char kPathSeparatorString[] = "/";
+const char kCurrentDirectoryString[] = "./";
+#endif // GTEST_OS_WINDOWS
+
+// Returns whether the given character is a valid path separator.
+static bool IsPathSeparator(char c) {
+#if GTEST_HAS_ALT_PATH_SEP_
+ return (c == kPathSeparator) || (c == kAlternatePathSeparator);
+#else
+ return c == kPathSeparator;
+#endif
+}
+
+// Returns the current working directory, or "" if unsuccessful.
+FilePath FilePath::GetCurrentDir() {
+#if GTEST_OS_WINDOWS_MOBILE
+ // Windows CE doesn't have a current directory, so we just return
+ // something reasonable.
+ return FilePath(kCurrentDirectoryString);
+#elif GTEST_OS_WINDOWS
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+ return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#else
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
+ return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns a copy of the FilePath with the case-insensitive extension removed.
+// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
+// FilePath("dir/file"). If a case-insensitive extension is not
+// found, returns a copy of the original FilePath.
+FilePath FilePath::RemoveExtension(const char* extension) const {
+ String dot_extension(String::Format(".%s", extension));
+ if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
+ return FilePath(String(pathname_.c_str(), pathname_.length() - 4));
+ }
+ return *this;
+}
+
+// Returns a pointer to the last occurence of a valid path separator in
+// the FilePath. On Windows, for example, both '/' and '\' are valid path
+// separators. Returns NULL if no path separator was found.
+const char* FilePath::FindLastPathSeparator() const {
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
+#if GTEST_HAS_ALT_PATH_SEP_
+ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
+ // Comparing two pointers of which only one is NULL is undefined.
+ if (last_alt_sep != NULL &&
+ (last_sep == NULL || last_alt_sep > last_sep)) {
+ return last_alt_sep;
+ }
+#endif
+ return last_sep;
+}
+
+// Returns a copy of the FilePath with the directory part removed.
+// Example: FilePath("path/to/file").RemoveDirectoryName() returns
+// FilePath("file"). If there is no directory part ("just_a_file"), it returns
+// the FilePath unmodified. If there is no file part ("just_a_dir/") it
+// returns an empty FilePath ("").
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveDirectoryName() const {
+ const char* const last_sep = FindLastPathSeparator();
+ return last_sep ? FilePath(String(last_sep + 1)) : *this;
+}
+
+// RemoveFileName returns the directory path with the filename removed.
+// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
+// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
+// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
+// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
+// On Windows platform, '\' is the path separator, otherwise it is '/'.
+FilePath FilePath::RemoveFileName() const {
+ const char* const last_sep = FindLastPathSeparator();
+ String dir;
+ if (last_sep) {
+ dir = String(c_str(), last_sep + 1 - c_str());
+ } else {
+ dir = kCurrentDirectoryString;
+ }
+ return FilePath(dir);
+}
+
+// Helper functions for naming files in a directory for xml output.
+
+// Given directory = "dir", base_name = "test", number = 0,
+// extension = "xml", returns "dir/test.xml". If number is greater
+// than zero (e.g., 12), returns "dir/test_12.xml".
+// On Windows platform, uses \ as the separator rather than /.
+FilePath FilePath::MakeFileName(const FilePath& directory,
+ const FilePath& base_name,
+ int number,
+ const char* extension) {
+ String file;
+ if (number == 0) {
+ file = String::Format("%s.%s", base_name.c_str(), extension);
+ } else {
+ file = String::Format("%s_%d.%s", base_name.c_str(), number, extension);
+ }
+ return ConcatPaths(directory, FilePath(file));
+}
+
+// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
+// On Windows, uses \ as the separator rather than /.
+FilePath FilePath::ConcatPaths(const FilePath& directory,
+ const FilePath& relative_path) {
+ if (directory.IsEmpty())
+ return relative_path;
+ const FilePath dir(directory.RemoveTrailingPathSeparator());
+ return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator,
+ relative_path.c_str()));
+}
+
+// Returns true if pathname describes something findable in the file-system,
+// either a file, directory, or whatever.
+bool FilePath::FileOrDirectoryExists() const {
+#if GTEST_OS_WINDOWS_MOBILE
+ LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ return attributes != kInvalidFileAttributes;
+#else
+ posix::StatStruct file_stat;
+ return posix::Stat(pathname_.c_str(), &file_stat) == 0;
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+// Returns true if pathname describes a directory in the file-system
+// that exists.
+bool FilePath::DirectoryExists() const {
+ bool result = false;
+#if GTEST_OS_WINDOWS
+ // Don't strip off trailing separator if path is a root directory on
+ // Windows (like "C:\\").
+ const FilePath& path(IsRootDirectory() ? *this :
+ RemoveTrailingPathSeparator());
+#else
+ const FilePath& path(*this);
+#endif
+
+#if GTEST_OS_WINDOWS_MOBILE
+ LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
+ const DWORD attributes = GetFileAttributes(unicode);
+ delete [] unicode;
+ if ((attributes != kInvalidFileAttributes) &&
+ (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ result = true;
+ }
+#else
+ posix::StatStruct file_stat;
+ result = posix::Stat(path.c_str(), &file_stat) == 0 &&
+ posix::IsDir(file_stat);
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ return result;
+}
+
+// Returns true if pathname describes a root directory. (Windows has one
+// root directory per disk drive.)
+bool FilePath::IsRootDirectory() const {
+#if GTEST_OS_WINDOWS
+ // TODO(wan@google.com): on Windows a network share like
+ // \\server\share can be a root directory, although it cannot be the
+ // current directory. Handle this properly.
+ return pathname_.length() == 3 && IsAbsolutePath();
+#else
+ return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
+#endif
+}
+
+// Returns true if pathname describes an absolute path.
+bool FilePath::IsAbsolutePath() const {
+ const char* const name = pathname_.c_str();
+#if GTEST_OS_WINDOWS
+ return pathname_.length() >= 3 &&
+ ((name[0] >= 'a' && name[0] <= 'z') ||
+ (name[0] >= 'A' && name[0] <= 'Z')) &&
+ name[1] == ':' &&
+ IsPathSeparator(name[2]);
+#else
+ return IsPathSeparator(name[0]);
+#endif
+}
+
+// Returns a pathname for a file that does not currently exist. The pathname
+// will be directory/base_name.extension or
+// directory/base_name_<number>.extension if directory/base_name.extension
+// already exists. The number will be incremented until a pathname is found
+// that does not already exist.
+// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
+// There could be a race condition if two or more processes are calling this
+// function at the same time -- they could both pick the same filename.
+FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
+ const FilePath& base_name,
+ const char* extension) {
+ FilePath full_pathname;
+ int number = 0;
+ do {
+ full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
+ } while (full_pathname.FileOrDirectoryExists());
+ return full_pathname;
+}
+
+// Returns true if FilePath ends with a path separator, which indicates that
+// it is intended to represent a directory. Returns false otherwise.
+// This does NOT check that a directory (or file) actually exists.
+bool FilePath::IsDirectory() const {
+ return !pathname_.empty() &&
+ IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
+}
+
+// Create directories so that path exists. Returns true if successful or if
+// the directories already exist; returns false if unable to create directories
+// for any reason.
+bool FilePath::CreateDirectoriesRecursively() const {
+ if (!this->IsDirectory()) {
+ return false;
+ }
+
+ if (pathname_.length() == 0 || this->DirectoryExists()) {
+ return true;
+ }
+
+ const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
+ return parent.CreateDirectoriesRecursively() && this->CreateFolder();
+}
+
+// Create the directory so that path exists. Returns true if successful or
+// if the directory already exists; returns false if unable to create the
+// directory for any reason, including if the parent directory does not
+// exist. Not named "CreateDirectory" because that's a macro on Windows.
+bool FilePath::CreateFolder() const {
+#if GTEST_OS_WINDOWS_MOBILE
+ FilePath removed_sep(this->RemoveTrailingPathSeparator());
+ LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
+ int result = CreateDirectory(unicode, NULL) ? 0 : -1;
+ delete [] unicode;
+#elif GTEST_OS_WINDOWS
+ int result = _mkdir(pathname_.c_str());
+#else
+ int result = mkdir(pathname_.c_str(), 0777);
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ if (result == -1) {
+ return this->DirectoryExists(); // An error is OK if the directory exists.
+ }
+ return true; // No error.
+}
+
+// If input name has a trailing separator character, remove it and return the
+// name, otherwise return the name string unmodified.
+// On Windows platform, uses \ as the separator, other platforms use /.
+FilePath FilePath::RemoveTrailingPathSeparator() const {
+ return IsDirectory()
+ ? FilePath(String(pathname_.c_str(), pathname_.length() - 1))
+ : *this;
+}
+
+// Removes any redundant separators that might be in the pathname.
+// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
+// redundancies that might be in a pathname involving "." or "..".
+// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
+void FilePath::Normalize() {
+ if (pathname_.c_str() == NULL) {
+ pathname_ = "";
+ return;
+ }
+ const char* src = pathname_.c_str();
+ char* const dest = new char[pathname_.length() + 1];
+ char* dest_ptr = dest;
+ memset(dest_ptr, 0, pathname_.length() + 1);
+
+ while (*src != '\0') {
+ *dest_ptr = *src;
+ if (!IsPathSeparator(*src)) {
+ src++;
+ } else {
+#if GTEST_HAS_ALT_PATH_SEP_
+ if (*dest_ptr == kAlternatePathSeparator) {
+ *dest_ptr = kPathSeparator;
+ }
+#endif
+ while (IsPathSeparator(*src))
+ src++;
+ }
+ dest_ptr++;
+ }
+ *dest_ptr = '\0';
+ pathname_ = dest;
+ delete[] dest;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/src/gtest-internal-inl.h b/Source/ThirdParty/gtest/src/gtest-internal-inl.h
new file mode 100644
index 000000000..855b21554
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest-internal-inl.h
@@ -0,0 +1,1074 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Utility functions and classes used by the Google C++ testing framework.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This file contains purely Google Test's internal implementation. Please
+// DO NOT #INCLUDE IT IN A USER PROGRAM.
+
+#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
+#define GTEST_SRC_GTEST_INTERNAL_INL_H_
+
+// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
+// part of Google Test's implementation; otherwise it's undefined.
+#if !GTEST_IMPLEMENTATION_
+// A user is trying to include this from his code - just say no.
+#error "gtest-internal-inl.h is part of Google Test's internal implementation."
+#error "It must not be included except by Google Test itself."
+#endif // GTEST_IMPLEMENTATION_
+
+#ifndef _WIN32_WCE
+#include <errno.h>
+#endif // !_WIN32_WCE
+#include <stddef.h>
+#include <stdlib.h> // For strtoll/_strtoul64/malloc/free.
+#include <string.h> // For memmove.
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <gtest/internal/gtest-port.h>
+
+#if GTEST_OS_WINDOWS
+#include <windows.h> // For DWORD.
+#endif // GTEST_OS_WINDOWS
+
+#include <gtest/gtest.h> // NOLINT
+#include <gtest/gtest-spi.h>
+
+namespace testing {
+
+// Declares the flags.
+//
+// We don't want the users to modify this flag in the code, but want
+// Google Test's own unit tests to be able to access it. Therefore we
+// declare it here as opposed to in gtest.h.
+GTEST_DECLARE_bool_(death_test_use_fork);
+
+namespace internal {
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;
+
+// Names of the flags (needed for parsing Google Test flags).
+const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
+const char kBreakOnFailureFlag[] = "break_on_failure";
+const char kCatchExceptionsFlag[] = "catch_exceptions";
+const char kColorFlag[] = "color";
+const char kFilterFlag[] = "filter";
+const char kListTestsFlag[] = "list_tests";
+const char kOutputFlag[] = "output";
+const char kPrintTimeFlag[] = "print_time";
+const char kRandomSeedFlag[] = "random_seed";
+const char kRepeatFlag[] = "repeat";
+const char kShuffleFlag[] = "shuffle";
+const char kStackTraceDepthFlag[] = "stack_trace_depth";
+const char kThrowOnFailureFlag[] = "throw_on_failure";
+
+// A valid random seed must be in [1, kMaxRandomSeed].
+const int kMaxRandomSeed = 99999;
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+GTEST_API_ extern bool g_help_flag;
+
+// Returns the current time in milliseconds.
+GTEST_API_ TimeInMillis GetTimeInMillis();
+
+// Returns true iff Google Test should use colors in the output.
+GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
+
+// Formats the given time in milliseconds as seconds.
+GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
+
+// Parses a string for an Int32 flag, in the form of "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+GTEST_API_ bool ParseInt32Flag(
+ const char* str, const char* flag, Int32* value);
+
+// Returns a random seed in range [1, kMaxRandomSeed] based on the
+// given --gtest_random_seed flag value.
+inline int GetRandomSeedFromFlag(Int32 random_seed_flag) {
+ const unsigned int raw_seed = (random_seed_flag == 0) ?
+ static_cast<unsigned int>(GetTimeInMillis()) :
+ static_cast<unsigned int>(random_seed_flag);
+
+ // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
+ // it's easy to type.
+ const int normalized_seed =
+ static_cast<int>((raw_seed - 1U) %
+ static_cast<unsigned int>(kMaxRandomSeed)) + 1;
+ return normalized_seed;
+}
+
+// Returns the first valid random seed after 'seed'. The behavior is
+// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is
+// considered to be 1.
+inline int GetNextRandomSeed(int seed) {
+ GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed)
+ << "Invalid random seed " << seed << " - must be in [1, "
+ << kMaxRandomSeed << "].";
+ const int next_seed = seed + 1;
+ return (next_seed > kMaxRandomSeed) ? 1 : next_seed;
+}
+
+// This class saves the values of all Google Test flags in its c'tor, and
+// restores them in its d'tor.
+class GTestFlagSaver {
+ public:
+ // The c'tor.
+ GTestFlagSaver() {
+ also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
+ break_on_failure_ = GTEST_FLAG(break_on_failure);
+ catch_exceptions_ = GTEST_FLAG(catch_exceptions);
+ color_ = GTEST_FLAG(color);
+ death_test_style_ = GTEST_FLAG(death_test_style);
+ death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
+ filter_ = GTEST_FLAG(filter);
+ internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
+ list_tests_ = GTEST_FLAG(list_tests);
+ output_ = GTEST_FLAG(output);
+ print_time_ = GTEST_FLAG(print_time);
+ random_seed_ = GTEST_FLAG(random_seed);
+ repeat_ = GTEST_FLAG(repeat);
+ shuffle_ = GTEST_FLAG(shuffle);
+ stack_trace_depth_ = GTEST_FLAG(stack_trace_depth);
+ throw_on_failure_ = GTEST_FLAG(throw_on_failure);
+ }
+
+ // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS.
+ ~GTestFlagSaver() {
+ GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
+ GTEST_FLAG(break_on_failure) = break_on_failure_;
+ GTEST_FLAG(catch_exceptions) = catch_exceptions_;
+ GTEST_FLAG(color) = color_;
+ GTEST_FLAG(death_test_style) = death_test_style_;
+ GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
+ GTEST_FLAG(filter) = filter_;
+ GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
+ GTEST_FLAG(list_tests) = list_tests_;
+ GTEST_FLAG(output) = output_;
+ GTEST_FLAG(print_time) = print_time_;
+ GTEST_FLAG(random_seed) = random_seed_;
+ GTEST_FLAG(repeat) = repeat_;
+ GTEST_FLAG(shuffle) = shuffle_;
+ GTEST_FLAG(stack_trace_depth) = stack_trace_depth_;
+ GTEST_FLAG(throw_on_failure) = throw_on_failure_;
+ }
+ private:
+ // Fields for saving the original values of flags.
+ bool also_run_disabled_tests_;
+ bool break_on_failure_;
+ bool catch_exceptions_;
+ String color_;
+ String death_test_style_;
+ bool death_test_use_fork_;
+ String filter_;
+ String internal_run_death_test_;
+ bool list_tests_;
+ String output_;
+ bool print_time_;
+ bool pretty_;
+ internal::Int32 random_seed_;
+ internal::Int32 repeat_;
+ bool shuffle_;
+ internal::Int32 stack_trace_depth_;
+ bool throw_on_failure_;
+} GTEST_ATTRIBUTE_UNUSED_;
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// The output buffer str must containt at least 32 characters.
+// The function returns the address of the output buffer.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'.
+GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str);
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars);
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded();
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (e.g., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+GTEST_API_ bool ShouldShard(const char* total_shards_str,
+ const char* shard_index_str,
+ bool in_subprocess_for_death_test);
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error and
+// and aborts.
+GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+GTEST_API_ bool ShouldRunTestOnShard(
+ int total_shards, int shard_index, int test_id);
+
+// STL container utilities.
+
+// Returns the number of elements in the given container that satisfy
+// the given predicate.
+template <class Container, typename Predicate>
+inline int CountIf(const Container& c, Predicate predicate) {
+ return static_cast<int>(std::count_if(c.begin(), c.end(), predicate));
+}
+
+// Applies a function/functor to each element in the container.
+template <class Container, typename Functor>
+void ForEach(const Container& c, Functor functor) {
+ std::for_each(c.begin(), c.end(), functor);
+}
+
+// Returns the i-th element of the vector, or default_value if i is not
+// in range [0, v.size()).
+template <typename E>
+inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
+ return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
+}
+
+// Performs an in-place shuffle of a range of the vector's elements.
+// 'begin' and 'end' are element indices as an STL-style range;
+// i.e. [begin, end) are shuffled, where 'end' == size() means to
+// shuffle to the end of the vector.
+template <typename E>
+void ShuffleRange(internal::Random* random, int begin, int end,
+ std::vector<E>* v) {
+ const int size = static_cast<int>(v->size());
+ GTEST_CHECK_(0 <= begin && begin <= size)
+ << "Invalid shuffle range start " << begin << ": must be in range [0, "
+ << size << "].";
+ GTEST_CHECK_(begin <= end && end <= size)
+ << "Invalid shuffle range finish " << end << ": must be in range ["
+ << begin << ", " << size << "].";
+
+ // Fisher-Yates shuffle, from
+ // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
+ for (int range_width = end - begin; range_width >= 2; range_width--) {
+ const int last_in_range = begin + range_width - 1;
+ const int selected = begin + random->Generate(range_width);
+ std::swap((*v)[selected], (*v)[last_in_range]);
+ }
+}
+
+// Performs an in-place shuffle of the vector's elements.
+template <typename E>
+inline void Shuffle(internal::Random* random, std::vector<E>* v) {
+ ShuffleRange(random, 0, static_cast<int>(v->size()), v);
+}
+
+// A function for deleting an object. Handy for being used as a
+// functor.
+template <typename T>
+static void Delete(T* x) {
+ delete x;
+}
+
+// A predicate that checks the key of a TestProperty against a known key.
+//
+// TestPropertyKeyIs is copyable.
+class TestPropertyKeyIs {
+ public:
+ // Constructor.
+ //
+ // TestPropertyKeyIs has NO default constructor.
+ explicit TestPropertyKeyIs(const char* key)
+ : key_(key) {}
+
+ // Returns true iff the test name of test property matches on key_.
+ bool operator()(const TestProperty& test_property) const {
+ return String(test_property.key()).Compare(key_) == 0;
+ }
+
+ private:
+ String key_;
+};
+
+class TestInfoImpl {
+ public:
+ TestInfoImpl(TestInfo* parent, const char* test_case_name,
+ const char* name, const char* test_case_comment,
+ const char* comment, TypeId fixture_class_id,
+ internal::TestFactoryBase* factory);
+ ~TestInfoImpl();
+
+ // Returns true if this test should run.
+ bool should_run() const { return should_run_; }
+
+ // Sets the should_run member.
+ void set_should_run(bool should) { should_run_ = should; }
+
+ // Returns true if this test is disabled. Disabled tests are not run.
+ bool is_disabled() const { return is_disabled_; }
+
+ // Sets the is_disabled member.
+ void set_is_disabled(bool is) { is_disabled_ = is; }
+
+ // Returns true if this test matches the filter specified by the user.
+ bool matches_filter() const { return matches_filter_; }
+
+ // Sets the matches_filter member.
+ void set_matches_filter(bool matches) { matches_filter_ = matches; }
+
+ // Returns the test case name.
+ const char* test_case_name() const { return test_case_name_.c_str(); }
+
+ // Returns the test name.
+ const char* name() const { return name_.c_str(); }
+
+ // Returns the test case comment.
+ const char* test_case_comment() const { return test_case_comment_.c_str(); }
+
+ // Returns the test comment.
+ const char* comment() const { return comment_.c_str(); }
+
+ // Returns the ID of the test fixture class.
+ TypeId fixture_class_id() const { return fixture_class_id_; }
+
+ // Returns the test result.
+ TestResult* result() { return &result_; }
+ const TestResult* result() const { return &result_; }
+
+ // Creates the test object, runs it, records its result, and then
+ // deletes it.
+ void Run();
+
+ // Clears the test result.
+ void ClearResult() { result_.Clear(); }
+
+ // Clears the test result in the given TestInfo object.
+ static void ClearTestResult(TestInfo * test_info) {
+ test_info->impl()->ClearResult();
+ }
+
+ private:
+ // These fields are immutable properties of the test.
+ TestInfo* const parent_; // The owner of this object
+ const String test_case_name_; // Test case name
+ const String name_; // Test name
+ const String test_case_comment_; // Test case comment
+ const String comment_; // Test comment
+ const TypeId fixture_class_id_; // ID of the test fixture class
+ bool should_run_; // True iff this test should run
+ bool is_disabled_; // True iff this test is disabled
+ bool matches_filter_; // True if this test matches the
+ // user-specified filter.
+ internal::TestFactoryBase* const factory_; // The factory that creates
+ // the test object
+
+ // This field is mutable and needs to be reset before running the
+ // test for the second time.
+ TestResult result_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl);
+};
+
+// Class UnitTestOptions.
+//
+// This class contains functions for processing options the user
+// specifies when running the tests. It has only static members.
+//
+// In most cases, the user can specify an option using either an
+// environment variable or a command line flag. E.g. you can set the
+// test filter using either GTEST_FILTER or --gtest_filter. If both
+// the variable and the flag are present, the latter overrides the
+// former.
+class GTEST_API_ UnitTestOptions {
+ public:
+ // Functions for processing the gtest_output flag.
+
+ // Returns the output format, or "" for normal printed output.
+ static String GetOutputFormat();
+
+ // Returns the absolute path of the requested output file, or the
+ // default (test_detail.xml in the original working directory) if
+ // none was explicitly specified.
+ static String GetAbsolutePathToOutputFile();
+
+ // Functions for processing the gtest_filter flag.
+
+ // Returns true iff the wildcard pattern matches the string. The
+ // first ':' or '\0' character in pattern marks the end of it.
+ //
+ // This recursive algorithm isn't very efficient, but is clear and
+ // works well enough for matching test names, which are short.
+ static bool PatternMatchesString(const char *pattern, const char *str);
+
+ // Returns true iff the user-specified filter matches the test case
+ // name and the test name.
+ static bool FilterMatchesTest(const String &test_case_name,
+ const String &test_name);
+
+#if GTEST_OS_WINDOWS
+ // Function for supporting the gtest_catch_exception flag.
+
+ // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+ // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+ // This function is useful as an __except condition.
+ static int GTestShouldProcessSEH(DWORD exception_code);
+#endif // GTEST_OS_WINDOWS
+
+ // Returns true if "name" matches the ':' separated list of glob-style
+ // filters in "filter".
+ static bool MatchesFilter(const String& name, const char* filter);
+};
+
+// Returns the current application's name, removing directory path if that
+// is present. Used by UnitTestOptions::GetOutputFile.
+GTEST_API_ FilePath GetCurrentExecutableName();
+
+// The role interface for getting the OS stack trace as a string.
+class OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetterInterface() {}
+ virtual ~OsStackTraceGetterInterface() {}
+
+ // Returns the current OS stack trace as a String. Parameters:
+ //
+ // max_depth - the maximum number of stack frames to be included
+ // in the trace.
+ // skip_count - the number of top frames to be skipped; doesn't count
+ // against max_depth.
+ virtual String CurrentStackTrace(int max_depth, int skip_count) = 0;
+
+ // UponLeavingGTest() should be called immediately before Google Test calls
+ // user code. It saves some information about the current stack that
+ // CurrentStackTrace() will use to find and hide Google Test stack frames.
+ virtual void UponLeavingGTest() = 0;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
+};
+
+// A working implementation of the OsStackTraceGetterInterface interface.
+class OsStackTraceGetter : public OsStackTraceGetterInterface {
+ public:
+ OsStackTraceGetter() : caller_frame_(NULL) {}
+ virtual String CurrentStackTrace(int max_depth, int skip_count);
+ virtual void UponLeavingGTest();
+
+ // This string is inserted in place of stack frames that are part of
+ // Google Test's implementation.
+ static const char* const kElidedFramesMarker;
+
+ private:
+ Mutex mutex_; // protects all internal state
+
+ // We save the stack frame below the frame that calls user code.
+ // We do this because the address of the frame immediately below
+ // the user code changes between the call to UponLeavingGTest()
+ // and any calls to CurrentStackTrace() from within the user code.
+ void* caller_frame_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
+};
+
+// Information about a Google Test trace point.
+struct TraceInfo {
+ const char* file;
+ int line;
+ String message;
+};
+
+// This is the default global test part result reporter used in UnitTestImpl.
+// This class should only be used by UnitTestImpl.
+class DefaultGlobalTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. Reports the test part
+ // result in the current test.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
+};
+
+// This is the default per thread test part result reporter used in
+// UnitTestImpl. This class should only be used by UnitTestImpl.
+class DefaultPerThreadTestPartResultReporter
+ : public TestPartResultReporterInterface {
+ public:
+ explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
+ // Implements the TestPartResultReporterInterface. The implementation just
+ // delegates to the current global test part result reporter of *unit_test_.
+ virtual void ReportTestPartResult(const TestPartResult& result);
+
+ private:
+ UnitTestImpl* const unit_test_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
+};
+
+// The private implementation of the UnitTest class. We don't protect
+// the methods under a mutex, as this class is not accessible by a
+// user and the UnitTest class that delegates work to this class does
+// proper locking.
+class GTEST_API_ UnitTestImpl {
+ public:
+ explicit UnitTestImpl(UnitTest* parent);
+ virtual ~UnitTestImpl();
+
+ // There are two different ways to register your own TestPartResultReporter.
+ // You can register your own repoter to listen either only for test results
+ // from the current thread or for results from all threads.
+ // By default, each per-thread test result repoter just passes a new
+ // TestPartResult to the global test result reporter, which registers the
+ // test part result for the currently running test.
+
+ // Returns the global test part result reporter.
+ TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
+
+ // Sets the global test part result reporter.
+ void SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter);
+
+ // Returns the test part result reporter for the current thread.
+ TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
+
+ // Sets the test part result reporter for the current thread.
+ void SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter);
+
+ // Gets the number of successful test cases.
+ int successful_test_case_count() const;
+
+ // Gets the number of failed test cases.
+ int failed_test_case_count() const;
+
+ // Gets the number of all test cases.
+ int total_test_case_count() const;
+
+ // Gets the number of all test cases that contain at least one test
+ // that should run.
+ int test_case_to_run_count() const;
+
+ // Gets the number of successful tests.
+ int successful_test_count() const;
+
+ // Gets the number of failed tests.
+ int failed_test_count() const;
+
+ // Gets the number of disabled tests.
+ int disabled_test_count() const;
+
+ // Gets the number of all tests.
+ int total_test_count() const;
+
+ // Gets the number of tests that should run.
+ int test_to_run_count() const;
+
+ // Gets the elapsed time, in milliseconds.
+ TimeInMillis elapsed_time() const { return elapsed_time_; }
+
+ // Returns true iff the unit test passed (i.e. all test cases passed).
+ bool Passed() const { return !Failed(); }
+
+ // Returns true iff the unit test failed (i.e. some test case failed
+ // or something outside of all tests failed).
+ bool Failed() const {
+ return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
+ }
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ const TestCase* GetTestCase(int i) const {
+ const int index = GetElementOr(test_case_indices_, i, -1);
+ return index < 0 ? NULL : test_cases_[i];
+ }
+
+ // Gets the i-th test case among all the test cases. i can range from 0 to
+ // total_test_case_count() - 1. If i is not in that range, returns NULL.
+ TestCase* GetMutableTestCase(int i) {
+ const int index = GetElementOr(test_case_indices_, i, -1);
+ return index < 0 ? NULL : test_cases_[index];
+ }
+
+ // Provides access to the event listener list.
+ TestEventListeners* listeners() { return &listeners_; }
+
+ // Returns the TestResult for the test that's currently running, or
+ // the TestResult for the ad hoc test if no test is running.
+ TestResult* current_test_result();
+
+ // Returns the TestResult for the ad hoc test.
+ const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }
+
+ // Sets the OS stack trace getter.
+ //
+ // Does nothing if the input and the current OS stack trace getter
+ // are the same; otherwise, deletes the old getter and makes the
+ // input the current getter.
+ void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
+
+ // Returns the current OS stack trace getter if it is not NULL;
+ // otherwise, creates an OsStackTraceGetter, makes it the current
+ // getter, and returns it.
+ OsStackTraceGetterInterface* os_stack_trace_getter();
+
+ // Returns the current OS stack trace as a String.
+ //
+ // The maximum number of stack frames to be included is specified by
+ // the gtest_stack_trace_depth flag. The skip_count parameter
+ // specifies the number of top frames to be skipped, which doesn't
+ // count against the number of frames to be included.
+ //
+ // For example, if Foo() calls Bar(), which in turn calls
+ // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+ // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+ String CurrentOsStackTraceExceptTop(int skip_count);
+
+ // Finds and returns a TestCase with the given name. If one doesn't
+ // exist, creates one and returns it.
+ //
+ // Arguments:
+ //
+ // test_case_name: name of the test case
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ TestCase* GetTestCase(const char* test_case_name,
+ const char* comment,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc);
+
+ // Adds a TestInfo to the unit test.
+ //
+ // Arguments:
+ //
+ // set_up_tc: pointer to the function that sets up the test case
+ // tear_down_tc: pointer to the function that tears down the test case
+ // test_info: the TestInfo object
+ void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc,
+ TestInfo * test_info) {
+ // In order to support thread-safe death tests, we need to
+ // remember the original working directory when the test program
+ // was first invoked. We cannot do this in RUN_ALL_TESTS(), as
+ // the user may have changed the current directory before calling
+ // RUN_ALL_TESTS(). Therefore we capture the current directory in
+ // AddTestInfo(), which is called to register a TEST or TEST_F
+ // before main() is reached.
+ if (original_working_dir_.IsEmpty()) {
+ original_working_dir_.Set(FilePath::GetCurrentDir());
+ GTEST_CHECK_(!original_working_dir_.IsEmpty())
+ << "Failed to get the current working directory.";
+ }
+
+ GetTestCase(test_info->test_case_name(),
+ test_info->test_case_comment(),
+ set_up_tc,
+ tear_down_tc)->AddTestInfo(test_info);
+ }
+
+#if GTEST_HAS_PARAM_TEST
+ // Returns ParameterizedTestCaseRegistry object used to keep track of
+ // value-parameterized tests and instantiate and register them.
+ internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
+ return parameterized_test_registry_;
+ }
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Sets the TestCase object for the test that's currently running.
+ void set_current_test_case(TestCase* a_current_test_case) {
+ current_test_case_ = a_current_test_case;
+ }
+
+ // Sets the TestInfo object for the test that's currently running. If
+ // current_test_info is NULL, the assertion results will be stored in
+ // ad_hoc_test_result_.
+ void set_current_test_info(TestInfo* a_current_test_info) {
+ current_test_info_ = a_current_test_info;
+ }
+
+ // Registers all parameterized tests defined using TEST_P and
+ // INSTANTIATE_TEST_P, creating regular tests for each test/parameter
+ // combination. This method can be called more then once; it has
+ // guards protecting from registering the tests more then once.
+ // If value-parameterized tests are disabled, RegisterParameterizedTests
+ // is present but does nothing.
+ void RegisterParameterizedTests();
+
+ // Runs all tests in this UnitTest object, prints the result, and
+ // returns 0 if all tests are successful, or 1 otherwise. If any
+ // exception is thrown during a test on Windows, this test is
+ // considered to be failed, but the rest of the tests will still be
+ // run. (We disable exceptions on Linux and Mac OS X, so the issue
+ // doesn't apply there.)
+ int RunAllTests();
+
+ // Clears the results of all tests, including the ad hoc test.
+ void ClearResult() {
+ ForEach(test_cases_, TestCase::ClearTestCaseResult);
+ ad_hoc_test_result_.Clear();
+ }
+
+ enum ReactionToSharding {
+ HONOR_SHARDING_PROTOCOL,
+ IGNORE_SHARDING_PROTOCOL
+ };
+
+ // Matches the full name of each test against the user-specified
+ // filter to decide whether the test should run, then records the
+ // result in each TestCase and TestInfo object.
+ // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
+ // based on sharding variables in the environment.
+ // Returns the number of tests that should run.
+ int FilterTests(ReactionToSharding shard_tests);
+
+ // Prints the names of the tests matching the user-specified filter flag.
+ void ListTestsMatchingFilter();
+
+ const TestCase* current_test_case() const { return current_test_case_; }
+ TestInfo* current_test_info() { return current_test_info_; }
+ const TestInfo* current_test_info() const { return current_test_info_; }
+
+ // Returns the vector of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ std::vector<Environment*>& environments() { return environments_; }
+
+ // Getters for the per-thread Google Test trace stack.
+ std::vector<TraceInfo>& gtest_trace_stack() {
+ return *(gtest_trace_stack_.pointer());
+ }
+ const std::vector<TraceInfo>& gtest_trace_stack() const {
+ return gtest_trace_stack_.get();
+ }
+
+#if GTEST_HAS_DEATH_TEST
+ void InitDeathTestSubprocessControlInfo() {
+ internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
+ }
+ // Returns a pointer to the parsed --gtest_internal_run_death_test
+ // flag, or NULL if that flag was not specified.
+ // This information is useful only in a death test child process.
+ // Must not be called before a call to InitGoogleTest.
+ const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
+ return internal_run_death_test_flag_.get();
+ }
+
+ // Returns a pointer to the current death test factory.
+ internal::DeathTestFactory* death_test_factory() {
+ return death_test_factory_.get();
+ }
+
+ void SuppressTestEventsIfInSubprocess();
+
+ friend class ReplaceDeathTestFactory;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Initializes the event listener performing XML output as specified by
+ // UnitTestOptions. Must not be called before InitGoogleTest.
+ void ConfigureXmlOutput();
+
+ // Performs initialization dependent upon flag values obtained in
+ // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
+ // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
+ // this function is also called from RunAllTests. Since this function can be
+ // called more than once, it has to be idempotent.
+ void PostFlagParsingInit();
+
+ // Gets the random seed used at the start of the current test iteration.
+ int random_seed() const { return random_seed_; }
+
+ // Gets the random number generator.
+ internal::Random* random() { return &random_; }
+
+ // Shuffles all test cases, and the tests within each test case,
+ // making sure that death tests are still run first.
+ void ShuffleTests();
+
+ // Restores the test cases and tests to their order before the first shuffle.
+ void UnshuffleTests();
+
+ private:
+ friend class ::testing::UnitTest;
+
+ // The UnitTest object that owns this implementation object.
+ UnitTest* const parent_;
+
+ // The working directory when the first TEST() or TEST_F() was
+ // executed.
+ internal::FilePath original_working_dir_;
+
+ // The default test part result reporters.
+ DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
+ DefaultPerThreadTestPartResultReporter
+ default_per_thread_test_part_result_reporter_;
+
+ // Points to (but doesn't own) the global test part result reporter.
+ TestPartResultReporterInterface* global_test_part_result_repoter_;
+
+ // Protects read and write access to global_test_part_result_reporter_.
+ internal::Mutex global_test_part_result_reporter_mutex_;
+
+ // Points to (but doesn't own) the per-thread test part result reporter.
+ internal::ThreadLocal<TestPartResultReporterInterface*>
+ per_thread_test_part_result_reporter_;
+
+ // The vector of environments that need to be set-up/torn-down
+ // before/after the tests are run.
+ std::vector<Environment*> environments_;
+
+ // The vector of TestCases in their original order. It owns the
+ // elements in the vector.
+ std::vector<TestCase*> test_cases_;
+
+ // Provides a level of indirection for the test case list to allow
+ // easy shuffling and restoring the test case order. The i-th
+ // element of this vector is the index of the i-th test case in the
+ // shuffled order.
+ std::vector<int> test_case_indices_;
+
+#if GTEST_HAS_PARAM_TEST
+ // ParameterizedTestRegistry object used to register value-parameterized
+ // tests.
+ internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
+
+ // Indicates whether RegisterParameterizedTests() has been called already.
+ bool parameterized_tests_registered_;
+#endif // GTEST_HAS_PARAM_TEST
+
+ // Index of the last death test case registered. Initially -1.
+ int last_death_test_case_;
+
+ // This points to the TestCase for the currently running test. It
+ // changes as Google Test goes through one test case after another.
+ // When no test is running, this is set to NULL and Google Test
+ // stores assertion results in ad_hoc_test_result_. Initially NULL.
+ TestCase* current_test_case_;
+
+ // This points to the TestInfo for the currently running test. It
+ // changes as Google Test goes through one test after another. When
+ // no test is running, this is set to NULL and Google Test stores
+ // assertion results in ad_hoc_test_result_. Initially NULL.
+ TestInfo* current_test_info_;
+
+ // Normally, a user only writes assertions inside a TEST or TEST_F,
+ // or inside a function called by a TEST or TEST_F. Since Google
+ // Test keeps track of which test is current running, it can
+ // associate such an assertion with the test it belongs to.
+ //
+ // If an assertion is encountered when no TEST or TEST_F is running,
+ // Google Test attributes the assertion result to an imaginary "ad hoc"
+ // test, and records the result in ad_hoc_test_result_.
+ TestResult ad_hoc_test_result_;
+
+ // The list of event listeners that can be used to track events inside
+ // Google Test.
+ TestEventListeners listeners_;
+
+ // The OS stack trace getter. Will be deleted when the UnitTest
+ // object is destructed. By default, an OsStackTraceGetter is used,
+ // but the user can set this field to use a custom getter if that is
+ // desired.
+ OsStackTraceGetterInterface* os_stack_trace_getter_;
+
+ // True iff PostFlagParsingInit() has been called.
+ bool post_flag_parse_init_performed_;
+
+ // The random number seed used at the beginning of the test run.
+ int random_seed_;
+
+ // Our random number generator.
+ internal::Random random_;
+
+ // How long the test took to run, in milliseconds.
+ TimeInMillis elapsed_time_;
+
+#if GTEST_HAS_DEATH_TEST
+ // The decomposed components of the gtest_internal_run_death_test flag,
+ // parsed when RUN_ALL_TESTS is called.
+ internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
+ internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
+#endif // GTEST_HAS_DEATH_TEST
+
+ // A per-thread stack of traces created by the SCOPED_TRACE() macro.
+ internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
+}; // class UnitTestImpl
+
+// Convenience function for accessing the global UnitTest
+// implementation object.
+inline UnitTestImpl* GetUnitTestImpl() {
+ return UnitTest::GetInstance()->impl();
+}
+
+// Internal helper functions for implementing the simple regular
+// expression matcher.
+GTEST_API_ bool IsInSet(char ch, const char* str);
+GTEST_API_ bool IsDigit(char ch);
+GTEST_API_ bool IsPunct(char ch);
+GTEST_API_ bool IsRepeat(char ch);
+GTEST_API_ bool IsWhiteSpace(char ch);
+GTEST_API_ bool IsWordChar(char ch);
+GTEST_API_ bool IsValidEscape(char ch);
+GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
+GTEST_API_ bool ValidateRegex(const char* regex);
+GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str);
+GTEST_API_ bool MatchRepetitionAndRegexAtHead(
+ bool escaped, char ch, char repeat, const char* regex, const char* str);
+GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str);
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
+GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
+
+#if GTEST_HAS_DEATH_TEST
+
+// Returns the message describing the last system error, regardless of the
+// platform.
+String GetLastErrnoDescription();
+
+#if GTEST_OS_WINDOWS
+// Provides leak-safe Windows kernel handle ownership.
+class AutoHandle {
+ public:
+ AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
+ explicit AutoHandle(HANDLE handle) : handle_(handle) {}
+
+ ~AutoHandle() { Reset(); }
+
+ HANDLE Get() const { return handle_; }
+ void Reset() { Reset(INVALID_HANDLE_VALUE); }
+ void Reset(HANDLE handle) {
+ if (handle != handle_) {
+ if (handle_ != INVALID_HANDLE_VALUE)
+ ::CloseHandle(handle_);
+ handle_ = handle;
+ }
+ }
+
+ private:
+ HANDLE handle_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+#endif // GTEST_OS_WINDOWS
+
+// Attempts to parse a string into a positive integer pointed to by the
+// number parameter. Returns true if that is possible.
+// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
+// it here.
+template <typename Integer>
+bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
+ // Fail fast if the given string does not begin with a digit;
+ // this bypasses strtoXXX's "optional leading whitespace and plus
+ // or minus sign" semantics, which are undesirable here.
+ if (str.empty() || !isdigit(str[0])) {
+ return false;
+ }
+ errno = 0;
+
+ char* end;
+ // BiggestConvertible is the largest integer type that system-provided
+ // string-to-number conversion routines can return.
+#if GTEST_OS_WINDOWS && !defined(__GNUC__)
+ // MSVC and C++ Builder define __int64 instead of the standard long long.
+ typedef unsigned __int64 BiggestConvertible;
+ const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
+#else
+ typedef unsigned long long BiggestConvertible; // NOLINT
+ const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
+#endif // GTEST_OS_WINDOWS && !defined(__GNUC__)
+ const bool parse_success = *end == '\0' && errno == 0;
+
+ // TODO(vladl@google.com): Convert this to compile time assertion when it is
+ // available.
+ GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
+
+ const Integer result = static_cast<Integer>(parsed);
+ if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
+ *number = result;
+ return true;
+ }
+ return false;
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// TestResult contains some private methods that should be hidden from
+// Google Test user but are required for testing. This class allow our tests
+// to access them.
+//
+// This class is supplied only for the purpose of testing Google Test's own
+// constructs. Do not use it in user tests, either directly or indirectly.
+class TestResultAccessor {
+ public:
+ static void RecordProperty(TestResult* test_result,
+ const TestProperty& property) {
+ test_result->RecordProperty(property);
+ }
+
+ static void ClearTestPartResults(TestResult* test_result) {
+ test_result->ClearTestPartResults();
+ }
+
+ static const std::vector<testing::TestPartResult>& test_part_results(
+ const TestResult& test_result) {
+ return test_result.test_part_results();
+ }
+};
+
+} // namespace internal
+} // namespace testing
+
+#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_
diff --git a/Source/ThirdParty/gtest/src/gtest-port.cc b/Source/ThirdParty/gtest/src/gtest-port.cc
new file mode 100644
index 000000000..b9504f56a
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest-port.cc
@@ -0,0 +1,711 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/internal/gtest-port.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+#include <windows.h> // For TerminateProcess()
+#elif GTEST_OS_WINDOWS
+#include <io.h>
+#include <sys/stat.h>
+#else
+#include <unistd.h>
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#if GTEST_OS_MAC
+#include <mach/mach_init.h>
+#include <mach/task.h>
+#include <mach/vm_map.h>
+#endif // GTEST_OS_MAC
+
+#include <gtest/gtest-spi.h>
+#include <gtest/gtest-message.h>
+#include <gtest/internal/gtest-string.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+namespace internal {
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
+const int kStdOutFileno = 1;
+const int kStdErrFileno = 2;
+#else
+const int kStdOutFileno = STDOUT_FILENO;
+const int kStdErrFileno = STDERR_FILENO;
+#endif // _MSC_VER
+
+#if GTEST_OS_MAC
+
+// Returns the number of threads running in the process, or 0 to indicate that
+// we cannot detect it.
+size_t GetThreadCount() {
+ const task_t task = mach_task_self();
+ mach_msg_type_number_t thread_count;
+ thread_act_array_t thread_list;
+ const kern_return_t status = task_threads(task, &thread_list, &thread_count);
+ if (status == KERN_SUCCESS) {
+ // task_threads allocates resources in thread_list and we need to free them
+ // to avoid leaks.
+ vm_deallocate(task,
+ reinterpret_cast<vm_address_t>(thread_list),
+ sizeof(thread_t) * thread_count);
+ return static_cast<size_t>(thread_count);
+ } else {
+ return 0;
+ }
+}
+
+#else
+
+size_t GetThreadCount() {
+ // There's no portable way to detect the number of threads, so we just
+ // return 0 to indicate that we cannot detect it.
+ return 0;
+}
+
+#endif // GTEST_OS_MAC
+
+#if GTEST_USES_POSIX_RE
+
+// Implements RE. Currently only needed for death tests.
+
+RE::~RE() {
+ if (is_valid_) {
+ // regfree'ing an invalid regex might crash because the content
+ // of the regex is undefined. Since the regex's are essentially
+ // the same, one cannot be valid (or invalid) without the other
+ // being so too.
+ regfree(&partial_regex_);
+ regfree(&full_regex_);
+ }
+ free(const_cast<char*>(pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+ if (!re.is_valid_) return false;
+
+ regmatch_t match;
+ return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+ pattern_ = posix::StrDup(regex);
+
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match.
+ const size_t full_regex_len = strlen(regex) + 10;
+ char* const full_pattern = new char[full_regex_len];
+
+ snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
+ is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
+ // We want to call regcomp(&partial_regex_, ...) even if the
+ // previous expression returns false. Otherwise partial_regex_ may
+ // not be properly initialized can may cause trouble when it's
+ // freed.
+ //
+ // Some implementation of POSIX regex (e.g. on at least some
+ // versions of Cygwin) doesn't accept the empty string as a valid
+ // regex. We change it to an equivalent form "()" to be safe.
+ if (is_valid_) {
+ const char* const partial_regex = (*regex == '\0') ? "()" : regex;
+ is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
+ }
+ EXPECT_TRUE(is_valid_)
+ << "Regular expression \"" << regex
+ << "\" is not a valid POSIX Extended regular expression.";
+
+ delete[] full_pattern;
+}
+
+#elif GTEST_USES_SIMPLE_RE
+
+// Returns true iff ch appears anywhere in str (excluding the
+// terminating '\0' character).
+bool IsInSet(char ch, const char* str) {
+ return ch != '\0' && strchr(str, ch) != NULL;
+}
+
+// Returns true iff ch belongs to the given classification. Unlike
+// similar functions in <ctype.h>, these aren't affected by the
+// current locale.
+bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; }
+bool IsPunct(char ch) {
+ return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
+}
+bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
+bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
+bool IsWordChar(char ch) {
+ return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
+ ('0' <= ch && ch <= '9') || ch == '_';
+}
+
+// Returns true iff "\\c" is a supported escape sequence.
+bool IsValidEscape(char c) {
+ return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW"));
+}
+
+// Returns true iff the given atom (specified by escaped and pattern)
+// matches ch. The result is undefined if the atom is invalid.
+bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
+ if (escaped) { // "\\p" where p is pattern_char.
+ switch (pattern_char) {
+ case 'd': return IsDigit(ch);
+ case 'D': return !IsDigit(ch);
+ case 'f': return ch == '\f';
+ case 'n': return ch == '\n';
+ case 'r': return ch == '\r';
+ case 's': return IsWhiteSpace(ch);
+ case 'S': return !IsWhiteSpace(ch);
+ case 't': return ch == '\t';
+ case 'v': return ch == '\v';
+ case 'w': return IsWordChar(ch);
+ case 'W': return !IsWordChar(ch);
+ }
+ return IsPunct(pattern_char) && pattern_char == ch;
+ }
+
+ return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
+}
+
+// Helper function used by ValidateRegex() to format error messages.
+String FormatRegexSyntaxError(const char* regex, int index) {
+ return (Message() << "Syntax error at index " << index
+ << " in simple regular expression \"" << regex << "\": ").GetString();
+}
+
+// Generates non-fatal failures and returns false if regex is invalid;
+// otherwise returns true.
+bool ValidateRegex(const char* regex) {
+ if (regex == NULL) {
+ // TODO(wan@google.com): fix the source file location in the
+ // assertion failures to match where the regex is used in user
+ // code.
+ ADD_FAILURE() << "NULL is not a valid simple regular expression.";
+ return false;
+ }
+
+ bool is_valid = true;
+
+ // True iff ?, *, or + can follow the previous atom.
+ bool prev_repeatable = false;
+ for (int i = 0; regex[i]; i++) {
+ if (regex[i] == '\\') { // An escape sequence
+ i++;
+ if (regex[i] == '\0') {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+ << "'\\' cannot appear at the end.";
+ return false;
+ }
+
+ if (!IsValidEscape(regex[i])) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
+ << "invalid escape sequence \"\\" << regex[i] << "\".";
+ is_valid = false;
+ }
+ prev_repeatable = true;
+ } else { // Not an escape sequence.
+ const char ch = regex[i];
+
+ if (ch == '^' && i > 0) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'^' can only appear at the beginning.";
+ is_valid = false;
+ } else if (ch == '$' && regex[i + 1] != '\0') {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'$' can only appear at the end.";
+ is_valid = false;
+ } else if (IsInSet(ch, "()[]{}|")) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'" << ch << "' is unsupported.";
+ is_valid = false;
+ } else if (IsRepeat(ch) && !prev_repeatable) {
+ ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
+ << "'" << ch << "' can only follow a repeatable token.";
+ is_valid = false;
+ }
+
+ prev_repeatable = !IsInSet(ch, "^$?*+");
+ }
+ }
+
+ return is_valid;
+}
+
+// Matches a repeated regex atom followed by a valid simple regular
+// expression. The regex atom is defined as c if escaped is false,
+// or \c otherwise. repeat is the repetition meta character (?, *,
+// or +). The behavior is undefined if str contains too many
+// characters to be indexable by size_t, in which case the test will
+// probably time out anyway. We are fine with this limitation as
+// std::string has it too.
+bool MatchRepetitionAndRegexAtHead(
+ bool escaped, char c, char repeat, const char* regex,
+ const char* str) {
+ const size_t min_count = (repeat == '+') ? 1 : 0;
+ const size_t max_count = (repeat == '?') ? 1 :
+ static_cast<size_t>(-1) - 1;
+ // We cannot call numeric_limits::max() as it conflicts with the
+ // max() macro on Windows.
+
+ for (size_t i = 0; i <= max_count; ++i) {
+ // We know that the atom matches each of the first i characters in str.
+ if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
+ // We have enough matches at the head, and the tail matches too.
+ // Since we only care about *whether* the pattern matches str
+ // (as opposed to *how* it matches), there is no need to find a
+ // greedy match.
+ return true;
+ }
+ if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
+ return false;
+ }
+ return false;
+}
+
+// Returns true iff regex matches a prefix of str. regex must be a
+// valid simple regular expression and not start with "^", or the
+// result is undefined.
+bool MatchRegexAtHead(const char* regex, const char* str) {
+ if (*regex == '\0') // An empty regex matches a prefix of anything.
+ return true;
+
+ // "$" only matches the end of a string. Note that regex being
+ // valid guarantees that there's nothing after "$" in it.
+ if (*regex == '$')
+ return *str == '\0';
+
+ // Is the first thing in regex an escape sequence?
+ const bool escaped = *regex == '\\';
+ if (escaped)
+ ++regex;
+ if (IsRepeat(regex[1])) {
+ // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
+ // here's an indirect recursion. It terminates as the regex gets
+ // shorter in each recursion.
+ return MatchRepetitionAndRegexAtHead(
+ escaped, regex[0], regex[1], regex + 2, str);
+ } else {
+ // regex isn't empty, isn't "$", and doesn't start with a
+ // repetition. We match the first atom of regex with the first
+ // character of str and recurse.
+ return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
+ MatchRegexAtHead(regex + 1, str + 1);
+ }
+}
+
+// Returns true iff regex matches any substring of str. regex must be
+// a valid simple regular expression, or the result is undefined.
+//
+// The algorithm is recursive, but the recursion depth doesn't exceed
+// the regex length, so we won't need to worry about running out of
+// stack space normally. In rare cases the time complexity can be
+// exponential with respect to the regex length + the string length,
+// but usually it's must faster (often close to linear).
+bool MatchRegexAnywhere(const char* regex, const char* str) {
+ if (regex == NULL || str == NULL)
+ return false;
+
+ if (*regex == '^')
+ return MatchRegexAtHead(regex + 1, str);
+
+ // A successful match can be anywhere in str.
+ do {
+ if (MatchRegexAtHead(regex, str))
+ return true;
+ } while (*str++ != '\0');
+ return false;
+}
+
+// Implements the RE class.
+
+RE::~RE() {
+ free(const_cast<char*>(pattern_));
+ free(const_cast<char*>(full_pattern_));
+}
+
+// Returns true iff regular expression re matches the entire str.
+bool RE::FullMatch(const char* str, const RE& re) {
+ return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
+}
+
+// Returns true iff regular expression re matches a substring of str
+// (including str itself).
+bool RE::PartialMatch(const char* str, const RE& re) {
+ return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
+}
+
+// Initializes an RE from its string representation.
+void RE::Init(const char* regex) {
+ pattern_ = full_pattern_ = NULL;
+ if (regex != NULL) {
+ pattern_ = posix::StrDup(regex);
+ }
+
+ is_valid_ = ValidateRegex(regex);
+ if (!is_valid_) {
+ // No need to calculate the full pattern when the regex is invalid.
+ return;
+ }
+
+ const size_t len = strlen(regex);
+ // Reserves enough bytes to hold the regular expression used for a
+ // full match: we need space to prepend a '^', append a '$', and
+ // terminate the string with '\0'.
+ char* buffer = static_cast<char*>(malloc(len + 3));
+ full_pattern_ = buffer;
+
+ if (*regex != '^')
+ *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'.
+
+ // We don't use snprintf or strncpy, as they trigger a warning when
+ // compiled with VC++ 8.0.
+ memcpy(buffer, regex, len);
+ buffer += len;
+
+ if (len == 0 || regex[len - 1] != '$')
+ *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'.
+
+ *buffer = '\0';
+}
+
+#endif // GTEST_USES_POSIX_RE
+
+
+GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
+ : severity_(severity) {
+ const char* const marker =
+ severity == GTEST_INFO ? "[ INFO ]" :
+ severity == GTEST_WARNING ? "[WARNING]" :
+ severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]";
+ GetStream() << ::std::endl << marker << " "
+ << FormatFileLocation(file, line).c_str() << ": ";
+}
+
+// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
+GTestLog::~GTestLog() {
+ GetStream() << ::std::endl;
+ if (severity_ == GTEST_FATAL) {
+ fflush(stderr);
+ posix::Abort();
+ }
+}
+// Disable Microsoft deprecation warnings for POSIX functions called from
+// this class (creat, dup, dup2, and close)
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4996)
+#endif // _MSC_VER
+
+#if GTEST_HAS_STREAM_REDIRECTION_
+
+// Object that captures an output stream (stdout/stderr).
+class CapturedStream {
+ public:
+ // The ctor redirects the stream to a temporary file.
+ CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
+#if GTEST_OS_WINDOWS
+ char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
+ char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
+
+ ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
+ const UINT success = ::GetTempFileNameA(temp_dir_path,
+ "gtest_redir",
+ 0, // Generate unique file name.
+ temp_file_path);
+ GTEST_CHECK_(success != 0)
+ << "Unable to create a temporary file in " << temp_dir_path;
+ const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
+ GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
+ << temp_file_path;
+ filename_ = temp_file_path;
+#else
+ // There's no guarantee that a test has write access to the
+ // current directory, so we create the temporary file in the /tmp
+ // directory instead.
+ char name_template[] = "/tmp/captured_stream.XXXXXX";
+ const int captured_fd = mkstemp(name_template);
+ filename_ = name_template;
+#endif // GTEST_OS_WINDOWS
+ fflush(NULL);
+ dup2(captured_fd, fd_);
+ close(captured_fd);
+ }
+
+ ~CapturedStream() {
+ remove(filename_.c_str());
+ }
+
+ String GetCapturedString() {
+ if (uncaptured_fd_ != -1) {
+ // Restores the original stream.
+ fflush(NULL);
+ dup2(uncaptured_fd_, fd_);
+ close(uncaptured_fd_);
+ uncaptured_fd_ = -1;
+ }
+
+ FILE* const file = posix::FOpen(filename_.c_str(), "r");
+ const String content = ReadEntireFile(file);
+ posix::FClose(file);
+ return content;
+ }
+
+ private:
+ // Reads the entire content of a file as a String.
+ static String ReadEntireFile(FILE* file);
+
+ // Returns the size (in bytes) of a file.
+ static size_t GetFileSize(FILE* file);
+
+ const int fd_; // A stream to capture.
+ int uncaptured_fd_;
+ // Name of the temporary file holding the stderr output.
+ ::std::string filename_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
+};
+
+// Returns the size (in bytes) of a file.
+size_t CapturedStream::GetFileSize(FILE* file) {
+ fseek(file, 0, SEEK_END);
+ return static_cast<size_t>(ftell(file));
+}
+
+// Reads the entire content of a file as a string.
+String CapturedStream::ReadEntireFile(FILE* file) {
+ const size_t file_size = GetFileSize(file);
+ char* const buffer = new char[file_size];
+
+ size_t bytes_last_read = 0; // # of bytes read in the last fread()
+ size_t bytes_read = 0; // # of bytes read so far
+
+ fseek(file, 0, SEEK_SET);
+
+ // Keeps reading the file until we cannot read further or the
+ // pre-determined file size is reached.
+ do {
+ bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+ bytes_read += bytes_last_read;
+ } while (bytes_last_read > 0 && bytes_read < file_size);
+
+ const String content(buffer, bytes_read);
+ delete[] buffer;
+
+ return content;
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+
+static CapturedStream* g_captured_stderr = NULL;
+static CapturedStream* g_captured_stdout = NULL;
+
+// Starts capturing an output stream (stdout/stderr).
+void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
+ if (*stream != NULL) {
+ GTEST_LOG_(FATAL) << "Only one " << stream_name
+ << " capturer can exist at a time.";
+ }
+ *stream = new CapturedStream(fd);
+}
+
+// Stops capturing the output stream and returns the captured string.
+String GetCapturedStream(CapturedStream** captured_stream) {
+ const String content = (*captured_stream)->GetCapturedString();
+
+ delete *captured_stream;
+ *captured_stream = NULL;
+
+ return content;
+}
+
+// Starts capturing stdout.
+void CaptureStdout() {
+ CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
+}
+
+// Starts capturing stderr.
+void CaptureStderr() {
+ CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
+}
+
+// Stops capturing stdout and returns the captured string.
+String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); }
+
+// Stops capturing stderr and returns the captured string.
+String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
+
+#endif // GTEST_HAS_STREAM_REDIRECTION_
+
+#if GTEST_HAS_DEATH_TEST
+
+// A copy of all command line arguments. Set by InitGoogleTest().
+::std::vector<String> g_argvs;
+
+// Returns the command line as a vector of strings.
+const ::std::vector<String>& GetArgvs() { return g_argvs; }
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_WINDOWS_MOBILE
+namespace posix {
+void Abort() {
+ DebugBreak();
+ TerminateProcess(GetCurrentProcess(), 1);
+}
+} // namespace posix
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Returns the name of the environment variable corresponding to the
+// given flag. For example, FlagToEnvVar("foo") will return
+// "GTEST_FOO" in the open-source version.
+static String FlagToEnvVar(const char* flag) {
+ const String full_flag =
+ (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
+
+ Message env_var;
+ for (size_t i = 0; i != full_flag.length(); i++) {
+ env_var << static_cast<char>(toupper(full_flag.c_str()[i]));
+ }
+
+ return env_var.GetString();
+}
+
+// Parses 'str' for a 32-bit signed integer. If successful, writes
+// the result to *value and returns true; otherwise leaves *value
+// unchanged and returns false.
+bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
+ // Parses the environment variable as a decimal integer.
+ char* end = NULL;
+ const long long_value = strtol(str, &end, 10); // NOLINT
+
+ // Has strtol() consumed all characters in the string?
+ if (*end != '\0') {
+ // No - an invalid character was encountered.
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value \"" << str << "\".\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ // Is the parsed value in the range of an Int32?
+ const Int32 result = static_cast<Int32>(long_value);
+ if (long_value == LONG_MAX || long_value == LONG_MIN ||
+ // The parsed value overflows as a long. (strtol() returns
+ // LONG_MAX or LONG_MIN when the input overflows.)
+ result != long_value
+ // The parsed value overflows as an Int32.
+ ) {
+ Message msg;
+ msg << "WARNING: " << src_text
+ << " is expected to be a 32-bit integer, but actually"
+ << " has value " << str << ", which overflows.\n";
+ printf("%s", msg.GetString().c_str());
+ fflush(stdout);
+ return false;
+ }
+
+ *value = result;
+ return true;
+}
+
+// Reads and returns the Boolean environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+//
+// The value is considered true iff it's not "0".
+bool BoolFromGTestEnv(const char* flag, bool default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ return string_value == NULL ?
+ default_value : strcmp(string_value, "0") != 0;
+}
+
+// Reads and returns a 32-bit integer stored in the environment
+// variable corresponding to the given flag; if it isn't set or
+// doesn't represent a valid 32-bit integer, returns default_value.
+Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const string_value = posix::GetEnv(env_var.c_str());
+ if (string_value == NULL) {
+ // The environment variable is not set.
+ return default_value;
+ }
+
+ Int32 result = default_value;
+ if (!ParseInt32(Message() << "Environment variable " << env_var,
+ string_value, &result)) {
+ printf("The default value %s is used.\n",
+ (Message() << default_value).GetString().c_str());
+ fflush(stdout);
+ return default_value;
+ }
+
+ return result;
+}
+
+// Reads and returns the string environment variable corresponding to
+// the given flag; if it's not set, returns default_value.
+const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+ const String env_var = FlagToEnvVar(flag);
+ const char* const value = posix::GetEnv(env_var.c_str());
+ return value == NULL ? default_value : value;
+}
+
+} // namespace internal
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/src/gtest-test-part.cc b/Source/ThirdParty/gtest/src/gtest-test-part.cc
new file mode 100644
index 000000000..5d183a446
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest-test-part.cc
@@ -0,0 +1,110 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include <gtest/gtest-test-part.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+using internal::GetUnitTestImpl;
+
+// Gets the summary of the failure message by omitting the stack trace
+// in it.
+internal::String TestPartResult::ExtractSummary(const char* message) {
+ const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
+ return stack_trace == NULL ? internal::String(message) :
+ internal::String(message, stack_trace - message);
+}
+
+// Prints a TestPartResult object.
+std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
+ return os
+ << result.file_name() << ":" << result.line_number() << ": "
+ << (result.type() == TestPartResult::kSuccess ? "Success" :
+ result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
+ "Non-fatal failure") << ":\n"
+ << result.message() << std::endl;
+}
+
+// Appends a TestPartResult to the array.
+void TestPartResultArray::Append(const TestPartResult& result) {
+ array_.push_back(result);
+}
+
+// Returns the TestPartResult at the given index (0-based).
+const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
+ if (index < 0 || index >= size()) {
+ printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
+ internal::posix::Abort();
+ }
+
+ return array_[index];
+}
+
+// Returns the number of TestPartResult objects in the array.
+int TestPartResultArray::size() const {
+ return static_cast<int>(array_.size());
+}
+
+namespace internal {
+
+HasNewFatalFailureHelper::HasNewFatalFailureHelper()
+ : has_new_fatal_failure_(false),
+ original_reporter_(GetUnitTestImpl()->
+ GetTestPartResultReporterForCurrentThread()) {
+ GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
+}
+
+HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
+ GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
+ original_reporter_);
+}
+
+void HasNewFatalFailureHelper::ReportTestPartResult(
+ const TestPartResult& result) {
+ if (result.fatally_failed())
+ has_new_fatal_failure_ = true;
+ original_reporter_->ReportTestPartResult(result);
+}
+
+} // namespace internal
+
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/src/gtest-typed-test.cc b/Source/ThirdParty/gtest/src/gtest-typed-test.cc
new file mode 100644
index 000000000..3cc4b5de2
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest-typed-test.cc
@@ -0,0 +1,110 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/gtest-typed-test.h>
+#include <gtest/gtest.h>
+
+namespace testing {
+namespace internal {
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// Skips to the first non-space char in str. Returns an empty string if str
+// contains only whitespace characters.
+static const char* SkipSpaces(const char* str) {
+ while (isspace(*str))
+ str++;
+ return str;
+}
+
+// Verifies that registered_tests match the test names in
+// defined_test_names_; returns registered_tests if successful, or
+// aborts the program otherwise.
+const char* TypedTestCasePState::VerifyRegisteredTestNames(
+ const char* file, int line, const char* registered_tests) {
+ typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+ registered_ = true;
+
+ // Skip initial whitespace in registered_tests since some
+ // preprocessors prefix stringizied literals with whitespace.
+ registered_tests = SkipSpaces(registered_tests);
+
+ Message errors;
+ ::std::set<String> tests;
+ for (const char* names = registered_tests; names != NULL;
+ names = SkipComma(names)) {
+ const String name = GetPrefixUntilComma(names);
+ if (tests.count(name) != 0) {
+ errors << "Test " << name << " is listed more than once.\n";
+ continue;
+ }
+
+ bool found = false;
+ for (DefinedTestIter it = defined_test_names_.begin();
+ it != defined_test_names_.end();
+ ++it) {
+ if (name == *it) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ tests.insert(name);
+ } else {
+ errors << "No test named " << name
+ << " can be found in this test case.\n";
+ }
+ }
+
+ for (DefinedTestIter it = defined_test_names_.begin();
+ it != defined_test_names_.end();
+ ++it) {
+ if (tests.count(*it) == 0) {
+ errors << "You forgot to list test " << *it << ".\n";
+ }
+ }
+
+ const String& errors_str = errors.GetString();
+ if (errors_str != "") {
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors_str.c_str());
+ fflush(stderr);
+ posix::Abort();
+ }
+
+ return registered_tests;
+}
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+} // namespace internal
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/src/gtest.cc b/Source/ThirdParty/gtest/src/gtest.cc
new file mode 100644
index 000000000..5b871c0ad
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest.cc
@@ -0,0 +1,4704 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// The Google C++ Testing Framework (Google Test)
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+#include <ctype.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <ostream>
+#include <sstream>
+#include <vector>
+
+#if GTEST_OS_LINUX
+
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+// Declares vsnprintf(). This header is not available on Windows.
+#include <strings.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#elif GTEST_OS_SYMBIAN
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+#include <sys/time.h> // NOLINT
+
+#elif GTEST_OS_ZOS
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+#include <sys/time.h> // NOLINT
+
+// On z/OS we additionally need strings.h for strcasecmp.
+#include <strings.h> // NOLINT
+
+#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE.
+
+#include <windows.h> // NOLINT
+
+#elif GTEST_OS_WINDOWS // We are on Windows proper.
+
+#include <io.h> // NOLINT
+#include <sys/timeb.h> // NOLINT
+#include <sys/types.h> // NOLINT
+#include <sys/stat.h> // NOLINT
+
+#if GTEST_OS_WINDOWS_MINGW
+// MinGW has gettimeofday() but not _ftime64().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+// TODO(kenton@google.com): There are other ways to get the time on
+// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW
+// supports these. consider using them instead.
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+#include <sys/time.h> // NOLINT
+#endif // GTEST_OS_WINDOWS_MINGW
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <windows.h> // NOLINT
+
+#else
+
+// Assume other platforms have gettimeofday().
+// TODO(kenton@google.com): Use autoconf to detect availability of
+// gettimeofday().
+#define GTEST_HAS_GETTIMEOFDAY_ 1
+
+// cpplint thinks that the header is already included, so we want to
+// silence it.
+#include <sys/time.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+#endif // GTEST_OS_LINUX
+
+#if GTEST_HAS_EXCEPTIONS
+#include <stdexcept>
+#endif
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_OS_WINDOWS
+#define vsnprintf _vsnprintf
+#endif // GTEST_OS_WINDOWS
+
+namespace testing {
+
+using internal::CountIf;
+using internal::ForEach;
+using internal::GetElementOr;
+using internal::Shuffle;
+
+// Constants.
+
+// A test whose test case name or test name matches this filter is
+// disabled and not run.
+static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
+
+// A test case whose name matches this filter is considered a death
+// test case and will be run before test cases whose name doesn't
+// match this filter.
+static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
+
+// A test filter that matches everything.
+static const char kUniversalFilter[] = "*";
+
+// The default output file for XML output.
+static const char kDefaultOutputFile[] = "test_detail.xml";
+
+// The environment variable name for the test shard index.
+static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+// The environment variable name for the total number of test shards.
+static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard status file.
+static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";
+
+namespace internal {
+
+// The text used in failure messages to indicate the start of the
+// stack trace.
+const char kStackTraceMarker[] = "\nStack trace:\n";
+
+// g_help_flag is true iff the --help flag or an equivalent form is
+// specified on the command line.
+bool g_help_flag = false;
+
+} // namespace internal
+
+GTEST_DEFINE_bool_(
+ also_run_disabled_tests,
+ internal::BoolFromGTestEnv("also_run_disabled_tests", false),
+ "Run disabled tests too, in addition to the tests normally being run.");
+
+GTEST_DEFINE_bool_(
+ break_on_failure,
+ internal::BoolFromGTestEnv("break_on_failure", false),
+ "True iff a failed assertion should be a debugger break-point.");
+
+GTEST_DEFINE_bool_(
+ catch_exceptions,
+ internal::BoolFromGTestEnv("catch_exceptions", false),
+ "True iff " GTEST_NAME_
+ " should catch exceptions and treat them as test failures.");
+
+GTEST_DEFINE_string_(
+ color,
+ internal::StringFromGTestEnv("color", "auto"),
+ "Whether to use colors in the output. Valid values: yes, no, "
+ "and auto. 'auto' means to use colors if the output is "
+ "being sent to a terminal and the TERM environment variable "
+ "is set to xterm, xterm-color, xterm-256color, linux or cygwin.");
+
+GTEST_DEFINE_string_(
+ filter,
+ internal::StringFromGTestEnv("filter", kUniversalFilter),
+ "A colon-separated list of glob (not regex) patterns "
+ "for filtering the tests to run, optionally followed by a "
+ "'-' and a : separated list of negative patterns (tests to "
+ "exclude). A test is run if it matches one of the positive "
+ "patterns and does not match any of the negative patterns.");
+
+GTEST_DEFINE_bool_(list_tests, false,
+ "List all tests without running them.");
+
+GTEST_DEFINE_string_(
+ output,
+ internal::StringFromGTestEnv("output", ""),
+ "A format (currently must be \"xml\"), optionally followed "
+ "by a colon and an output file name or directory. A directory "
+ "is indicated by a trailing pathname separator. "
+ "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
+ "If a directory is specified, output files will be created "
+ "within that directory, with file-names based on the test "
+ "executable's name and, if necessary, made unique by adding "
+ "digits.");
+
+GTEST_DEFINE_bool_(
+ print_time,
+ internal::BoolFromGTestEnv("print_time", true),
+ "True iff " GTEST_NAME_
+ " should display elapsed time in text output.");
+
+GTEST_DEFINE_int32_(
+ random_seed,
+ internal::Int32FromGTestEnv("random_seed", 0),
+ "Random number seed to use when shuffling test orders. Must be in range "
+ "[1, 99999], or 0 to use a seed based on the current time.");
+
+GTEST_DEFINE_int32_(
+ repeat,
+ internal::Int32FromGTestEnv("repeat", 1),
+ "How many times to repeat each test. Specify a negative number "
+ "for repeating forever. Useful for shaking out flaky tests.");
+
+GTEST_DEFINE_bool_(
+ show_internal_stack_frames, false,
+ "True iff " GTEST_NAME_ " should include internal stack frames when "
+ "printing test failure stack traces.");
+
+GTEST_DEFINE_bool_(
+ shuffle,
+ internal::BoolFromGTestEnv("shuffle", false),
+ "True iff " GTEST_NAME_
+ " should randomize tests' order on every run.");
+
+GTEST_DEFINE_int32_(
+ stack_trace_depth,
+ internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
+ "The maximum number of stack frames to print when an "
+ "assertion fails. The valid range is 0 through 100, inclusive.");
+
+GTEST_DEFINE_bool_(
+ throw_on_failure,
+ internal::BoolFromGTestEnv("throw_on_failure", false),
+ "When this flag is specified, a failed assertion will throw an exception "
+ "if exceptions are enabled or exit the program with a non-zero code "
+ "otherwise.");
+
+namespace internal {
+
+// Generates a random number from [0, range), using a Linear
+// Congruential Generator (LCG). Crashes if 'range' is 0 or greater
+// than kMaxRange.
+UInt32 Random::Generate(UInt32 range) {
+ // These constants are the same as are used in glibc's rand(3).
+ state_ = (1103515245U*state_ + 12345U) % kMaxRange;
+
+ GTEST_CHECK_(range > 0)
+ << "Cannot generate a number in the range [0, 0).";
+ GTEST_CHECK_(range <= kMaxRange)
+ << "Generation of a number in [0, " << range << ") was requested, "
+ << "but this can only generate numbers in [0, " << kMaxRange << ").";
+
+ // Converting via modulus introduces a bit of downward bias, but
+ // it's simple, and a linear congruential generator isn't too good
+ // to begin with.
+ return state_ % range;
+}
+
+// GTestIsInitialized() returns true iff the user has initialized
+// Google Test. Useful for catching the user mistake of not initializing
+// Google Test before calling RUN_ALL_TESTS().
+//
+// A user must call testing::InitGoogleTest() to initialize Google
+// Test. g_init_gtest_count is set to the number of times
+// InitGoogleTest() has been called. We don't protect this variable
+// under a mutex as it is only accessed in the main thread.
+int g_init_gtest_count = 0;
+static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+
+// Iterates over a vector of TestCases, keeping a running sum of the
+// results of calling a given int-returning method on each.
+// Returns the sum.
+static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
+ int (TestCase::*method)() const) {
+ int sum = 0;
+ for (size_t i = 0; i < case_list.size(); i++) {
+ sum += (case_list[i]->*method)();
+ }
+ return sum;
+}
+
+// Returns true iff the test case passed.
+static bool TestCasePassed(const TestCase* test_case) {
+ return test_case->should_run() && test_case->Passed();
+}
+
+// Returns true iff the test case failed.
+static bool TestCaseFailed(const TestCase* test_case) {
+ return test_case->should_run() && test_case->Failed();
+}
+
+// Returns true iff test_case contains at least one test that should
+// run.
+static bool ShouldRunTestCase(const TestCase* test_case) {
+ return test_case->should_run();
+}
+
+// AssertHelper constructor.
+AssertHelper::AssertHelper(TestPartResult::Type type,
+ const char* file,
+ int line,
+ const char* message)
+ : data_(new AssertHelperData(type, file, line, message)) {
+}
+
+AssertHelper::~AssertHelper() {
+ delete data_;
+}
+
+// Message assignment, for assertion streaming support.
+void AssertHelper::operator=(const Message& message) const {
+ UnitTest::GetInstance()->
+ AddTestPartResult(data_->type, data_->file, data_->line,
+ AppendUserMessage(data_->message, message),
+ UnitTest::GetInstance()->impl()
+ ->CurrentOsStackTraceExceptTop(1)
+ // Skips the stack frame for this function itself.
+ ); // NOLINT
+}
+
+// Mutex for linked pointers.
+GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
+
+// Application pathname gotten in InitGoogleTest.
+String g_executable_path;
+
+// Returns the current application's name, removing directory path if that
+// is present.
+FilePath GetCurrentExecutableName() {
+ FilePath result;
+
+#if GTEST_OS_WINDOWS
+ result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+#else
+ result.Set(FilePath(g_executable_path));
+#endif // GTEST_OS_WINDOWS
+
+ return result.RemoveDirectoryName();
+}
+
+// Functions for processing the gtest_output flag.
+
+// Returns the output format, or "" for normal printed output.
+String UnitTestOptions::GetOutputFormat() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL) return String("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ return (colon == NULL) ?
+ String(gtest_output_flag) :
+ String(gtest_output_flag, colon - gtest_output_flag);
+}
+
+// Returns the name of the requested output file, or the default if none
+// was explicitly specified.
+String UnitTestOptions::GetAbsolutePathToOutputFile() {
+ const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
+ if (gtest_output_flag == NULL)
+ return String("");
+
+ const char* const colon = strchr(gtest_output_flag, ':');
+ if (colon == NULL)
+ return String(internal::FilePath::ConcatPaths(
+ internal::FilePath(
+ UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(kDefaultOutputFile)).ToString() );
+
+ internal::FilePath output_name(colon + 1);
+ if (!output_name.IsAbsolutePath())
+ // TODO(wan@google.com): on Windows \some\path is not an absolute
+ // path (as its meaning depends on the current drive), yet the
+ // following logic for turning it into an absolute path is wrong.
+ // Fix it.
+ output_name = internal::FilePath::ConcatPaths(
+ internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
+ internal::FilePath(colon + 1));
+
+ if (!output_name.IsDirectory())
+ return output_name.ToString();
+
+ internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
+ output_name, internal::GetCurrentExecutableName(),
+ GetOutputFormat().c_str()));
+ return result.ToString();
+}
+
+// Returns true iff the wildcard pattern matches the string. The
+// first ':' or '\0' character in pattern marks the end of it.
+//
+// This recursive algorithm isn't very efficient, but is clear and
+// works well enough for matching test names, which are short.
+bool UnitTestOptions::PatternMatchesString(const char *pattern,
+ const char *str) {
+ switch (*pattern) {
+ case '\0':
+ case ':': // Either ':' or '\0' marks the end of the pattern.
+ return *str == '\0';
+ case '?': // Matches any single character.
+ return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
+ case '*': // Matches any string (possibly empty) of characters.
+ return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+ PatternMatchesString(pattern + 1, str);
+ default: // Non-special character. Matches itself.
+ return *pattern == *str &&
+ PatternMatchesString(pattern + 1, str + 1);
+ }
+}
+
+bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) {
+ const char *cur_pattern = filter;
+ for (;;) {
+ if (PatternMatchesString(cur_pattern, name.c_str())) {
+ return true;
+ }
+
+ // Finds the next pattern in the filter.
+ cur_pattern = strchr(cur_pattern, ':');
+
+ // Returns if no more pattern can be found.
+ if (cur_pattern == NULL) {
+ return false;
+ }
+
+ // Skips the pattern separater (the ':' character).
+ cur_pattern++;
+ }
+}
+
+// TODO(keithray): move String function implementations to gtest-string.cc.
+
+// Returns true iff the user-specified filter matches the test case
+// name and the test name.
+bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,
+ const String &test_name) {
+ const String& full_name = String::Format("%s.%s",
+ test_case_name.c_str(),
+ test_name.c_str());
+
+ // Split --gtest_filter at '-', if there is one, to separate into
+ // positive filter and negative filter portions
+ const char* const p = GTEST_FLAG(filter).c_str();
+ const char* const dash = strchr(p, '-');
+ String positive;
+ String negative;
+ if (dash == NULL) {
+ positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
+ negative = String("");
+ } else {
+ positive = String(p, dash - p); // Everything up to the dash
+ negative = String(dash+1); // Everything after the dash
+ if (positive.empty()) {
+ // Treat '-test1' as the same as '*-test1'
+ positive = kUniversalFilter;
+ }
+ }
+
+ // A filter is a colon-separated list of patterns. It matches a
+ // test if any pattern in it matches the test.
+ return (MatchesFilter(full_name, positive.c_str()) &&
+ !MatchesFilter(full_name, negative.c_str()));
+}
+
+#if GTEST_OS_WINDOWS
+// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
+// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
+// This function is useful as an __except condition.
+int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
+ // Google Test should handle an exception if:
+ // 1. the user wants it to, AND
+ // 2. this is not a breakpoint exception.
+ return (GTEST_FLAG(catch_exceptions) &&
+ exception_code != EXCEPTION_BREAKPOINT) ?
+ EXCEPTION_EXECUTE_HANDLER :
+ EXCEPTION_CONTINUE_SEARCH;
+}
+#endif // GTEST_OS_WINDOWS
+
+} // namespace internal
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results. Intercepts only failures from the current thread.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ TestPartResultArray* result)
+ : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
+ result_(result) {
+ Init();
+}
+
+// The c'tor sets this object as the test part result reporter used by
+// Google Test. The 'result' parameter specifies where to report the
+// results.
+ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
+ InterceptMode intercept_mode, TestPartResultArray* result)
+ : intercept_mode_(intercept_mode),
+ result_(result) {
+ Init();
+}
+
+void ScopedFakeTestPartResultReporter::Init() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ old_reporter_ = impl->GetGlobalTestPartResultReporter();
+ impl->SetGlobalTestPartResultReporter(this);
+ } else {
+ old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
+ impl->SetTestPartResultReporterForCurrentThread(this);
+ }
+}
+
+// The d'tor restores the test part result reporter used by Google Test
+// before.
+ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
+ impl->SetGlobalTestPartResultReporter(old_reporter_);
+ } else {
+ impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
+ }
+}
+
+// Increments the test part result count and remembers the result.
+// This method is from the TestPartResultReporterInterface interface.
+void ScopedFakeTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ result_->Append(result);
+}
+
+namespace internal {
+
+// Returns the type ID of ::testing::Test. We should always call this
+// instead of GetTypeId< ::testing::Test>() to get the type ID of
+// testing::Test. This is to work around a suspected linker bug when
+// using Google Test as a framework on Mac OS X. The bug causes
+// GetTypeId< ::testing::Test>() to return different values depending
+// on whether the call is from the Google Test framework itself or
+// from user test code. GetTestTypeId() is guaranteed to always
+// return the same value, as it always calls GetTypeId<>() from the
+// gtest.cc, which is within the Google Test framework.
+TypeId GetTestTypeId() {
+ return GetTypeId<Test>();
+}
+
+// The value of GetTestTypeId() as seen from within the Google Test
+// library. This is solely for testing GetTestTypeId().
+extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
+
+// This predicate-formatter checks that 'results' contains a test part
+// failure of the given type and that the failure message contains the
+// given substring.
+AssertionResult HasOneFailure(const char* /* results_expr */,
+ const char* /* type_expr */,
+ const char* /* substr_expr */,
+ const TestPartResultArray& results,
+ TestPartResult::Type type,
+ const char* substr) {
+ const String expected(type == TestPartResult::kFatalFailure ?
+ "1 fatal failure" :
+ "1 non-fatal failure");
+ Message msg;
+ if (results.size() != 1) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual: " << results.size() << " failures";
+ for (int i = 0; i < results.size(); i++) {
+ msg << "\n" << results.GetTestPartResult(i);
+ }
+ return AssertionFailure(msg);
+ }
+
+ const TestPartResult& r = results.GetTestPartResult(0);
+ if (r.type() != type) {
+ msg << "Expected: " << expected << "\n"
+ << " Actual:\n"
+ << r;
+ return AssertionFailure(msg);
+ }
+
+ if (strstr(r.message(), substr) == NULL) {
+ msg << "Expected: " << expected << " containing \""
+ << substr << "\"\n"
+ << " Actual:\n"
+ << r;
+ return AssertionFailure(msg);
+ }
+
+ return AssertionSuccess();
+}
+
+// The constructor of SingleFailureChecker remembers where to look up
+// test part results, what type of failure we expect, and what
+// substring the failure message should contain.
+SingleFailureChecker:: SingleFailureChecker(
+ const TestPartResultArray* results,
+ TestPartResult::Type type,
+ const char* substr)
+ : results_(results),
+ type_(type),
+ substr_(substr) {}
+
+// The destructor of SingleFailureChecker verifies that the given
+// TestPartResultArray contains exactly one failure that has the given
+// type and contains the given substring. If that's not the case, a
+// non-fatal failure will be generated.
+SingleFailureChecker::~SingleFailureChecker() {
+ EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str());
+}
+
+DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ unit_test_->current_test_result()->AddTestPartResult(result);
+ unit_test_->listeners()->repeater()->OnTestPartResult(result);
+}
+
+DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
+ UnitTestImpl* unit_test) : unit_test_(unit_test) {}
+
+void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
+ const TestPartResult& result) {
+ unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
+}
+
+// Returns the global test part result reporter.
+TestPartResultReporterInterface*
+UnitTestImpl::GetGlobalTestPartResultReporter() {
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ return global_test_part_result_repoter_;
+}
+
+// Sets the global test part result reporter.
+void UnitTestImpl::SetGlobalTestPartResultReporter(
+ TestPartResultReporterInterface* reporter) {
+ internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
+ global_test_part_result_repoter_ = reporter;
+}
+
+// Returns the test part result reporter for the current thread.
+TestPartResultReporterInterface*
+UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
+ return per_thread_test_part_result_reporter_.get();
+}
+
+// Sets the test part result reporter for the current thread.
+void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
+ TestPartResultReporterInterface* reporter) {
+ per_thread_test_part_result_reporter_.set(reporter);
+}
+
+// Gets the number of successful test cases.
+int UnitTestImpl::successful_test_case_count() const {
+ return CountIf(test_cases_, TestCasePassed);
+}
+
+// Gets the number of failed test cases.
+int UnitTestImpl::failed_test_case_count() const {
+ return CountIf(test_cases_, TestCaseFailed);
+}
+
+// Gets the number of all test cases.
+int UnitTestImpl::total_test_case_count() const {
+ return static_cast<int>(test_cases_.size());
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTestImpl::test_case_to_run_count() const {
+ return CountIf(test_cases_, ShouldRunTestCase);
+}
+
+// Gets the number of successful tests.
+int UnitTestImpl::successful_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
+}
+
+// Gets the number of failed tests.
+int UnitTestImpl::failed_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
+}
+
+// Gets the number of disabled tests.
+int UnitTestImpl::disabled_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
+}
+
+// Gets the number of all tests.
+int UnitTestImpl::total_test_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
+}
+
+// Gets the number of tests that should run.
+int UnitTestImpl::test_to_run_count() const {
+ return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
+// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
+String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
+ (void)skip_count;
+ return String("");
+}
+
+// Returns the current time in milliseconds.
+TimeInMillis GetTimeInMillis() {
+#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__)
+ // Difference between 1970-01-01 and 1601-01-01 in milliseconds.
+ // http://analogous.blogspot.com/2005/04/epoch.html
+ const TimeInMillis kJavaEpochToWinFileTimeDelta =
+ static_cast<TimeInMillis>(116444736UL) * 100000UL;
+ const DWORD kTenthMicrosInMilliSecond = 10000;
+
+ SYSTEMTIME now_systime;
+ FILETIME now_filetime;
+ ULARGE_INTEGER now_int64;
+ // TODO(kenton@google.com): Shouldn't this just use
+ // GetSystemTimeAsFileTime()?
+ GetSystemTime(&now_systime);
+ if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
+ now_int64.LowPart = now_filetime.dwLowDateTime;
+ now_int64.HighPart = now_filetime.dwHighDateTime;
+ now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
+ kJavaEpochToWinFileTimeDelta;
+ return now_int64.QuadPart;
+ }
+ return 0;
+#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
+ __timeb64 now;
+#ifdef _MSC_VER
+ // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
+ // (deprecated function) there.
+ // TODO(kenton@google.com): Use GetTickCount()? Or use
+ // SystemTimeToFileTime()
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ _ftime64(&now);
+#pragma warning(pop) // Restores the warning state.
+#else
+ _ftime64(&now);
+#endif // _MSC_VER
+ return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
+#elif GTEST_HAS_GETTIMEOFDAY_
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
+#else
+#error "Don't know how to get the current time on your system."
+#endif
+}
+
+// Utilities
+
+// class String
+
+// Returns the input enclosed in double quotes if it's not NULL;
+// otherwise returns "(null)". For example, "\"Hello\"" is returned
+// for input "Hello".
+//
+// This is useful for printing a C string in the syntax of a literal.
+//
+// Known issue: escape sequences are not handled yet.
+String String::ShowCStringQuoted(const char* c_str) {
+ return c_str ? String::Format("\"%s\"", c_str) : String("(null)");
+}
+
+// Copies at most length characters from str into a newly-allocated
+// piece of memory of size length+1. The memory is allocated with new[].
+// A terminating null byte is written to the memory, and a pointer to it
+// is returned. If str is NULL, NULL is returned.
+static char* CloneString(const char* str, size_t length) {
+ if (str == NULL) {
+ return NULL;
+ } else {
+ char* const clone = new char[length + 1];
+ posix::StrNCpy(clone, str, length);
+ clone[length] = '\0';
+ return clone;
+ }
+}
+
+// Clones a 0-terminated C string, allocating memory using new. The
+// caller is responsible for deleting[] the return value. Returns the
+// cloned string, or NULL if the input is NULL.
+const char * String::CloneCString(const char* c_str) {
+ return (c_str == NULL) ?
+ NULL : CloneString(c_str, strlen(c_str));
+}
+
+#if GTEST_OS_WINDOWS_MOBILE
+// Creates a UTF-16 wide string from the given ANSI string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the wide string, or NULL if the
+// input is NULL.
+LPCWSTR String::AnsiToUtf16(const char* ansi) {
+ if (!ansi) return NULL;
+ const int length = strlen(ansi);
+ const int unicode_length =
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ NULL, 0);
+ WCHAR* unicode = new WCHAR[unicode_length + 1];
+ MultiByteToWideChar(CP_ACP, 0, ansi, length,
+ unicode, unicode_length);
+ unicode[unicode_length] = 0;
+ return unicode;
+}
+
+// Creates an ANSI string from the given wide string, allocating
+// memory using new. The caller is responsible for deleting the return
+// value using delete[]. Returns the ANSI string, or NULL if the
+// input is NULL.
+const char* String::Utf16ToAnsi(LPCWSTR utf16_str) {
+ if (!utf16_str) return NULL;
+ const int ansi_length =
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+ NULL, 0, NULL, NULL);
+ char* ansi = new char[ansi_length + 1];
+ WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
+ ansi, ansi_length, NULL, NULL);
+ ansi[ansi_length] = 0;
+ return ansi;
+}
+
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Compares two C strings. Returns true iff they have the same content.
+//
+// Unlike strcmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CStringEquals(const char * lhs, const char * rhs) {
+ if ( lhs == NULL ) return rhs == NULL;
+
+ if ( rhs == NULL ) return false;
+
+ return strcmp(lhs, rhs) == 0;
+}
+
+#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+// Converts an array of wide chars to a narrow string using the UTF-8
+// encoding, and streams the result to the given Message object.
+static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
+ Message* msg) {
+ // TODO(wan): consider allowing a testing::String object to
+ // contain '\0'. This will make it behave more like std::string,
+ // and will allow ToUtf8String() to return the correct encoding
+ // for '\0' s.t. we can get rid of the conditional here (and in
+ // several other places).
+ for (size_t i = 0; i != length; ) { // NOLINT
+ if (wstr[i] != L'\0') {
+ *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
+ while (i != length && wstr[i] != L'\0')
+ i++;
+ } else {
+ *msg << '\0';
+ i++;
+ }
+ }
+}
+
+#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
+
+} // namespace internal
+
+#if GTEST_HAS_STD_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::std::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+// Converts the given wide string to a narrow string using the UTF-8
+// encoding, and streams the result to this Message object.
+Message& Message::operator <<(const ::wstring& wstr) {
+ internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
+ return *this;
+}
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+namespace internal {
+
+// Formats a value to be used in a failure message.
+
+// For a char value, we print it as a C++ char literal and as an
+// unsigned integer (both in decimal and in hexadecimal).
+String FormatForFailureMessage(char ch) {
+ const unsigned int ch_as_uint = ch;
+ // A String object cannot contain '\0', so we print "\\0" when ch is
+ // '\0'.
+ return String::Format("'%s' (%u, 0x%X)",
+ ch ? String::Format("%c", ch).c_str() : "\\0",
+ ch_as_uint, ch_as_uint);
+}
+
+// For a wchar_t value, we print it as a C++ wchar_t literal and as an
+// unsigned integer (both in decimal and in hexidecimal).
+String FormatForFailureMessage(wchar_t wchar) {
+ // The C++ standard doesn't specify the exact size of the wchar_t
+ // type. It just says that it shall have the same size as another
+ // integral type, called its underlying type.
+ //
+ // Therefore, in order to print a wchar_t value in the numeric form,
+ // we first convert it to the largest integral type (UInt64) and
+ // then print the converted value.
+ //
+ // We use streaming to print the value as "%llu" doesn't work
+ // correctly with MSVC 7.1.
+ const UInt64 wchar_as_uint64 = wchar;
+ Message msg;
+ // A String object cannot contain '\0', so we print "\\0" when wchar is
+ // L'\0'.
+ char buffer[32]; // CodePointToUtf8 requires a buffer that big.
+ msg << "L'"
+ << (wchar ? CodePointToUtf8(static_cast<UInt32>(wchar), buffer) : "\\0")
+ << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16)
+ << wchar_as_uint64 << ")";
+ return msg.GetString();
+}
+
+} // namespace internal
+
+// AssertionResult constructors.
+// Used in EXPECT_TRUE/FALSE(assertion_result).
+AssertionResult::AssertionResult(const AssertionResult& other)
+ : success_(other.success_),
+ message_(other.message_.get() != NULL ?
+ new internal::String(*other.message_) :
+ static_cast<internal::String*>(NULL)) {
+}
+
+// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
+AssertionResult AssertionResult::operator!() const {
+ AssertionResult negation(!success_);
+ if (message_.get() != NULL)
+ negation << *message_;
+ return negation;
+}
+
+// Makes a successful assertion result.
+AssertionResult AssertionSuccess() {
+ return AssertionResult(true);
+}
+
+// Makes a failed assertion result.
+AssertionResult AssertionFailure() {
+ return AssertionResult(false);
+}
+
+// Makes a failed assertion result with the given failure message.
+// Deprecated; use AssertionFailure() << message.
+AssertionResult AssertionFailure(const Message& message) {
+ return AssertionFailure() << message;
+}
+
+namespace internal {
+
+// Constructs and returns the message for an equality assertion
+// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
+//
+// The first four parameters are the expressions used in the assertion
+// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
+// where foo is 5 and bar is 6, we have:
+//
+// expected_expression: "foo"
+// actual_expression: "bar"
+// expected_value: "5"
+// actual_value: "6"
+//
+// The ignoring_case parameter is true iff the assertion is a
+// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
+// be inserted into the message.
+AssertionResult EqFailure(const char* expected_expression,
+ const char* actual_expression,
+ const String& expected_value,
+ const String& actual_value,
+ bool ignoring_case) {
+ Message msg;
+ msg << "Value of: " << actual_expression;
+ if (actual_value != actual_expression) {
+ msg << "\n Actual: " << actual_value;
+ }
+
+ msg << "\nExpected: " << expected_expression;
+ if (ignoring_case) {
+ msg << " (ignoring case)";
+ }
+ if (expected_value != expected_expression) {
+ msg << "\nWhich is: " << expected_value;
+ }
+
+ return AssertionFailure(msg);
+}
+
+// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
+String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result,
+ const char* expression_text,
+ const char* actual_predicate_value,
+ const char* expected_predicate_value) {
+ const char* actual_message = assertion_result.message();
+ Message msg;
+ msg << "Value of: " << expression_text
+ << "\n Actual: " << actual_predicate_value;
+ if (actual_message[0] != '\0')
+ msg << " (" << actual_message << ")";
+ msg << "\nExpected: " << expected_predicate_value;
+ return msg.GetString();
+}
+
+// Helper function for implementing ASSERT_NEAR.
+AssertionResult DoubleNearPredFormat(const char* expr1,
+ const char* expr2,
+ const char* abs_error_expr,
+ double val1,
+ double val2,
+ double abs_error) {
+ const double diff = fabs(val1 - val2);
+ if (diff <= abs_error) return AssertionSuccess();
+
+ // TODO(wan): do not print the value of an expression if it's
+ // already a literal.
+ Message msg;
+ msg << "The difference between " << expr1 << " and " << expr2
+ << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
+ << expr1 << " evaluates to " << val1 << ",\n"
+ << expr2 << " evaluates to " << val2 << ", and\n"
+ << abs_error_expr << " evaluates to " << abs_error << ".";
+ return AssertionFailure(msg);
+}
+
+
+// Helper template for implementing FloatLE() and DoubleLE().
+template <typename RawType>
+AssertionResult FloatingPointLE(const char* expr1,
+ const char* expr2,
+ RawType val1,
+ RawType val2) {
+ // Returns success if val1 is less than val2,
+ if (val1 < val2) {
+ return AssertionSuccess();
+ }
+
+ // or if val1 is almost equal to val2.
+ const FloatingPoint<RawType> lhs(val1), rhs(val2);
+ if (lhs.AlmostEquals(rhs)) {
+ return AssertionSuccess();
+ }
+
+ // Note that the above two checks will both fail if either val1 or
+ // val2 is NaN, as the IEEE floating-point standard requires that
+ // any predicate involving a NaN must return false.
+
+ StrStream val1_ss;
+ val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val1;
+
+ StrStream val2_ss;
+ val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+ << val2;
+
+ Message msg;
+ msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
+ << " Actual: " << StrStreamToString(&val1_ss) << " vs "
+ << StrStreamToString(&val2_ss);
+
+ return AssertionFailure(msg);
+}
+
+} // namespace internal
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult FloatLE(const char* expr1, const char* expr2,
+ float val1, float val2) {
+ return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
+}
+
+// Asserts that val1 is less than, or almost equal to, val2. Fails
+// otherwise. In particular, it fails if either val1 or val2 is NaN.
+AssertionResult DoubleLE(const char* expr1, const char* expr2,
+ double val1, double val2) {
+ return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
+}
+
+namespace internal {
+
+// The helper function for {ASSERT|EXPECT}_EQ with int or enum
+// arguments.
+AssertionResult CmpHelperEQ(const char* expected_expression,
+ const char* actual_expression,
+ BiggestInt expected,
+ BiggestInt actual) {
+ if (expected == actual) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ FormatForComparisonFailureMessage(expected, actual),
+ FormatForComparisonFailureMessage(actual, expected),
+ false);
+}
+
+// A macro for implementing the helper functions needed to implement
+// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here
+// just to avoid copy-and-paste of similar code.
+#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
+AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
+ BiggestInt val1, BiggestInt val2) {\
+ if (val1 op val2) {\
+ return AssertionSuccess();\
+ } else {\
+ Message msg;\
+ msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
+ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
+ << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+ return AssertionFailure(msg);\
+ }\
+}
+
+// Implements the helper function for {ASSERT|EXPECT}_NE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(NE, !=)
+// Implements the helper function for {ASSERT|EXPECT}_LE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LE, <=)
+// Implements the helper function for {ASSERT|EXPECT}_LT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(LT, < )
+// Implements the helper function for {ASSERT|EXPECT}_GE with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GE, >=)
+// Implements the helper function for {ASSERT|EXPECT}_GT with int or
+// enum arguments.
+GTEST_IMPL_CMP_HELPER_(GT, > )
+
+#undef GTEST_IMPL_CMP_HELPER_
+
+// The helper function for {ASSERT|EXPECT}_STREQ.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual) {
+ if (String::CStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowCStringQuoted(expected),
+ String::ShowCStringQuoted(actual),
+ false);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
+AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
+ const char* actual_expression,
+ const char* expected,
+ const char* actual) {
+ if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowCStringQuoted(expected),
+ String::ShowCStringQuoted(actual),
+ true);
+}
+
+// The helper function for {ASSERT|EXPECT}_STRNE.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ return AssertionFailure(msg);
+ }
+}
+
+// The helper function for {ASSERT|EXPECT}_STRCASENE.
+AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
+ const char* s2_expression,
+ const char* s1,
+ const char* s2) {
+ if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ } else {
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << ") (ignoring case), actual: \""
+ << s1 << "\" vs \"" << s2 << "\"";
+ return AssertionFailure(msg);
+ }
+}
+
+} // namespace internal
+
+namespace {
+
+// Helper functions for implementing IsSubString() and IsNotSubstring().
+
+// This group of overloaded functions return true iff needle is a
+// substring of haystack. NULL is considered a substring of itself
+// only.
+
+bool IsSubstringPred(const char* needle, const char* haystack) {
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return strstr(haystack, needle) != NULL;
+}
+
+bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
+ if (needle == NULL || haystack == NULL)
+ return needle == haystack;
+
+ return wcsstr(haystack, needle) != NULL;
+}
+
+// StringType here can be either ::std::string or ::std::wstring.
+template <typename StringType>
+bool IsSubstringPred(const StringType& needle,
+ const StringType& haystack) {
+ return haystack.find(needle) != StringType::npos;
+}
+
+// This function implements either IsSubstring() or IsNotSubstring(),
+// depending on the value of the expected_to_be_substring parameter.
+// StringType here can be const char*, const wchar_t*, ::std::string,
+// or ::std::wstring.
+template <typename StringType>
+AssertionResult IsSubstringImpl(
+ bool expected_to_be_substring,
+ const char* needle_expr, const char* haystack_expr,
+ const StringType& needle, const StringType& haystack) {
+ if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
+ return AssertionSuccess();
+
+ const bool is_wide_string = sizeof(needle[0]) > 1;
+ const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
+ return AssertionFailure(
+ Message()
+ << "Value of: " << needle_expr << "\n"
+ << " Actual: " << begin_string_quote << needle << "\"\n"
+ << "Expected: " << (expected_to_be_substring ? "" : "not ")
+ << "a substring of " << haystack_expr << "\n"
+ << "Which is: " << begin_string_quote << haystack << "\"");
+}
+
+} // namespace
+
+// IsSubstring() and IsNotSubstring() check whether needle is a
+// substring of haystack (NULL is considered a substring of itself
+// only), and return an appropriate error message when they fail.
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const char* needle, const char* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const wchar_t* needle, const wchar_t* haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::string& needle, const ::std::string& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+
+#if GTEST_HAS_STD_WSTRING
+AssertionResult IsSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
+}
+
+AssertionResult IsNotSubstring(
+ const char* needle_expr, const char* haystack_expr,
+ const ::std::wstring& needle, const ::std::wstring& haystack) {
+ return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
+}
+#endif // GTEST_HAS_STD_WSTRING
+
+namespace internal {
+
+#if GTEST_OS_WINDOWS
+
+namespace {
+
+// Helper function for IsHRESULT{SuccessFailure} predicates
+AssertionResult HRESULTFailureHelper(const char* expr,
+ const char* expected,
+ long hr) { // NOLINT
+#if GTEST_OS_WINDOWS_MOBILE
+ // Windows CE doesn't support FormatMessage.
+ const char error_text[] = "";
+#else
+ // Looks up the human-readable system message for the HRESULT code
+ // and since we're not passing any params to FormatMessage, we don't
+ // want inserts expanded.
+ const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS;
+ const DWORD kBufSize = 4096; // String::Format can't exceed this length.
+ // Gets the system's human readable message string for this HRESULT.
+ char error_text[kBufSize] = { '\0' };
+ DWORD message_length = ::FormatMessageA(kFlags,
+ 0, // no source, we're asking system
+ hr, // the error
+ 0, // no line width restrictions
+ error_text, // output buffer
+ kBufSize, // buf size
+ NULL); // no arguments for inserts
+ // Trims tailing white space (FormatMessage leaves a trailing cr-lf)
+ for (; message_length && isspace(error_text[message_length - 1]);
+ --message_length) {
+ error_text[message_length - 1] = '\0';
+ }
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+ const String error_hex(String::Format("0x%08X ", hr));
+ Message msg;
+ msg << "Expected: " << expr << " " << expected << ".\n"
+ << " Actual: " << error_hex << error_text << "\n";
+
+ return ::testing::AssertionFailure(msg);
+}
+
+} // namespace
+
+AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT
+ if (SUCCEEDED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "succeeds", hr);
+}
+
+AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT
+ if (FAILED(hr)) {
+ return AssertionSuccess();
+ }
+ return HRESULTFailureHelper(expr, "fails", hr);
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Utility functions for encoding Unicode text (wide strings) in
+// UTF-8.
+
+// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
+// like this:
+//
+// Code-point length Encoding
+// 0 - 7 bits 0xxxxxxx
+// 8 - 11 bits 110xxxxx 10xxxxxx
+// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx
+// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+
+// The maximum code-point a one-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) << 7) - 1;
+
+// The maximum code-point a two-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
+
+// The maximum code-point a three-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
+
+// The maximum code-point a four-byte UTF-8 sequence can represent.
+const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
+
+// Chops off the n lowest bits from a bit pattern. Returns the n
+// lowest bits. As a side effect, the original bit pattern will be
+// shifted to the right by n bits.
+inline UInt32 ChopLowBits(UInt32* bits, int n) {
+ const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
+ *bits >>= n;
+ return low_bits;
+}
+
+// Converts a Unicode code point to a narrow string in UTF-8 encoding.
+// code_point parameter is of type UInt32 because wchar_t may not be
+// wide enough to contain a code point.
+// The output buffer str must containt at least 32 characters.
+// The function returns the address of the output buffer.
+// If the code_point is not a valid Unicode code point
+// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'.
+char* CodePointToUtf8(UInt32 code_point, char* str) {
+ if (code_point <= kMaxCodePoint1) {
+ str[1] = '\0';
+ str[0] = static_cast<char>(code_point); // 0xxxxxxx
+ } else if (code_point <= kMaxCodePoint2) {
+ str[2] = '\0';
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xC0 | code_point); // 110xxxxx
+ } else if (code_point <= kMaxCodePoint3) {
+ str[3] = '\0';
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xE0 | code_point); // 1110xxxx
+ } else if (code_point <= kMaxCodePoint4) {
+ str[4] = '\0';
+ str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
+ str[0] = static_cast<char>(0xF0 | code_point); // 11110xxx
+ } else {
+ // The longest string String::Format can produce when invoked
+ // with these parameters is 28 character long (not including
+ // the terminating nul character). We are asking for 32 character
+ // buffer just in case. This is also enough for strncpy to
+ // null-terminate the destination string.
+ posix::StrNCpy(
+ str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32);
+ str[31] = '\0'; // Makes sure no change in the format to strncpy leaves
+ // the result unterminated.
+ }
+ return str;
+}
+
+// The following two functions only make sense if the the system
+// uses UTF-16 for wide string encoding. All supported systems
+// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
+
+// Determines if the arguments constitute UTF-16 surrogate pair
+// and thus should be combined into a single Unicode code point
+// using CreateCodePointFromUtf16SurrogatePair.
+inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
+ return sizeof(wchar_t) == 2 &&
+ (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
+}
+
+// Creates a Unicode code point from UTF16 surrogate pair.
+inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
+ wchar_t second) {
+ const UInt32 mask = (1 << 10) - 1;
+ return (sizeof(wchar_t) == 2) ?
+ (((first & mask) << 10) | (second & mask)) + 0x10000 :
+ // This function should not be called when the condition is
+ // false, but we provide a sensible default in case it is.
+ static_cast<UInt32>(first);
+}
+
+// Converts a wide string to a narrow string in UTF-8 encoding.
+// The wide string is assumed to have the following encoding:
+// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
+// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
+// Parameter str points to a null-terminated wide string.
+// Parameter num_chars may additionally limit the number
+// of wchar_t characters processed. -1 is used when the entire string
+// should be processed.
+// If the string contains code points that are not valid Unicode code points
+// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
+// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
+// and contains invalid UTF-16 surrogate pairs, values in those pairs
+// will be encoded as individual Unicode characters from Basic Normal Plane.
+String WideStringToUtf8(const wchar_t* str, int num_chars) {
+ if (num_chars == -1)
+ num_chars = static_cast<int>(wcslen(str));
+
+ StrStream stream;
+ for (int i = 0; i < num_chars; ++i) {
+ UInt32 unicode_code_point;
+
+ if (str[i] == L'\0') {
+ break;
+ } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
+ unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
+ str[i + 1]);
+ i++;
+ } else {
+ unicode_code_point = static_cast<UInt32>(str[i]);
+ }
+
+ char buffer[32]; // CodePointToUtf8 requires a buffer this big.
+ stream << CodePointToUtf8(unicode_code_point, buffer);
+ }
+ return StrStreamToString(&stream);
+}
+
+// Converts a wide C string to a String using the UTF-8 encoding.
+// NULL will be converted to "(null)".
+String String::ShowWideCString(const wchar_t * wide_c_str) {
+ if (wide_c_str == NULL) return String("(null)");
+
+ return String(internal::WideStringToUtf8(wide_c_str, -1).c_str());
+}
+
+// Similar to ShowWideCString(), except that this function encloses
+// the converted string in double quotes.
+String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) {
+ if (wide_c_str == NULL) return String("(null)");
+
+ return String::Format("L\"%s\"",
+ String::ShowWideCString(wide_c_str).c_str());
+}
+
+// Compares two wide C strings. Returns true iff they have the same
+// content.
+//
+// Unlike wcscmp(), this function can handle NULL argument(s). A NULL
+// C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
+ if (lhs == NULL) return rhs == NULL;
+
+ if (rhs == NULL) return false;
+
+ return wcscmp(lhs, rhs) == 0;
+}
+
+// Helper function for *_STREQ on wide strings.
+AssertionResult CmpHelperSTREQ(const char* expected_expression,
+ const char* actual_expression,
+ const wchar_t* expected,
+ const wchar_t* actual) {
+ if (String::WideCStringEquals(expected, actual)) {
+ return AssertionSuccess();
+ }
+
+ return EqFailure(expected_expression,
+ actual_expression,
+ String::ShowWideCStringQuoted(expected),
+ String::ShowWideCStringQuoted(actual),
+ false);
+}
+
+// Helper function for *_STRNE on wide strings.
+AssertionResult CmpHelperSTRNE(const char* s1_expression,
+ const char* s2_expression,
+ const wchar_t* s1,
+ const wchar_t* s2) {
+ if (!String::WideCStringEquals(s1, s2)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << "Expected: (" << s1_expression << ") != ("
+ << s2_expression << "), actual: "
+ << String::ShowWideCStringQuoted(s1)
+ << " vs " << String::ShowWideCStringQuoted(s2);
+ return AssertionFailure(msg);
+}
+
+// Compares two C strings, ignoring case. Returns true iff they have
+// the same content.
+//
+// Unlike strcasecmp(), this function can handle NULL argument(s). A
+// NULL C string is considered different to any non-NULL C string,
+// including the empty string.
+bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
+ if (lhs == NULL)
+ return rhs == NULL;
+ if (rhs == NULL)
+ return false;
+ return posix::StrCaseCmp(lhs, rhs) == 0;
+}
+
+ // Compares two wide C strings, ignoring case. Returns true iff they
+ // have the same content.
+ //
+ // Unlike wcscasecmp(), this function can handle NULL argument(s).
+ // A NULL C string is considered different to any non-NULL wide C string,
+ // including the empty string.
+ // NB: The implementations on different platforms slightly differ.
+ // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
+ // environment variable. On GNU platform this method uses wcscasecmp
+ // which compares according to LC_CTYPE category of the current locale.
+ // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
+ // current locale.
+bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
+ const wchar_t* rhs) {
+ if ( lhs == NULL ) return rhs == NULL;
+
+ if ( rhs == NULL ) return false;
+
+#if GTEST_OS_WINDOWS
+ return _wcsicmp(lhs, rhs) == 0;
+#elif GTEST_OS_LINUX
+ return wcscasecmp(lhs, rhs) == 0;
+#else
+ // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes
+ // may not define it either.
+ wint_t left, right;
+ do {
+ left = towlower(*lhs++);
+ right = towlower(*rhs++);
+ } while (left && left == right);
+ return left == right;
+#endif // OS selector
+}
+
+// Compares this with another String.
+// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
+// if this is greater than rhs.
+int String::Compare(const String & rhs) const {
+ const char* const lhs_c_str = c_str();
+ const char* const rhs_c_str = rhs.c_str();
+
+ if (lhs_c_str == NULL) {
+ return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL
+ } else if (rhs_c_str == NULL) {
+ return 1;
+ }
+
+ const size_t shorter_str_len =
+ length() <= rhs.length() ? length() : rhs.length();
+ for (size_t i = 0; i != shorter_str_len; i++) {
+ if (lhs_c_str[i] < rhs_c_str[i]) {
+ return -1;
+ } else if (lhs_c_str[i] > rhs_c_str[i]) {
+ return 1;
+ }
+ }
+ return (length() < rhs.length()) ? -1 :
+ (length() > rhs.length()) ? 1 : 0;
+}
+
+// Returns true iff this String ends with the given suffix. *Any*
+// String is considered to end with a NULL or empty suffix.
+bool String::EndsWith(const char* suffix) const {
+ if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+ if (c_str() == NULL) return false;
+
+ const size_t this_len = strlen(c_str());
+ const size_t suffix_len = strlen(suffix);
+ return (this_len >= suffix_len) &&
+ CStringEquals(c_str() + this_len - suffix_len, suffix);
+}
+
+// Returns true iff this String ends with the given suffix, ignoring case.
+// Any String is considered to end with a NULL or empty suffix.
+bool String::EndsWithCaseInsensitive(const char* suffix) const {
+ if (suffix == NULL || CStringEquals(suffix, "")) return true;
+
+ if (c_str() == NULL) return false;
+
+ const size_t this_len = strlen(c_str());
+ const size_t suffix_len = strlen(suffix);
+ return (this_len >= suffix_len) &&
+ CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix);
+}
+
+// Formats a list of arguments to a String, using the same format
+// spec string as for printf.
+//
+// We do not use the StringPrintf class as it is not universally
+// available.
+//
+// The result is limited to 4096 characters (including the tailing 0).
+// If 4096 characters are not enough to format the input, or if
+// there's an error, "<formatting error or buffer exceeded>" is
+// returned.
+String String::Format(const char * format, ...) {
+ va_list args;
+ va_start(args, format);
+
+ char buffer[4096];
+ const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]);
+
+ // MSVC 8 deprecates vsnprintf(), so we want to suppress warning
+ // 4996 (deprecated function) there.
+#ifdef _MSC_VER // We are using MSVC.
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4996) // Temporarily disables warning 4996.
+ const int size = vsnprintf(buffer, kBufferSize, format, args);
+#pragma warning(pop) // Restores the warning state.
+#else // We are not using MSVC.
+ const int size = vsnprintf(buffer, kBufferSize, format, args);
+#endif // _MSC_VER
+ va_end(args);
+
+ // vsnprintf()'s behavior is not portable. When the buffer is not
+ // big enough, it returns a negative value in MSVC, and returns the
+ // needed buffer size on Linux. When there is an output error, it
+ // always returns a negative value. For simplicity, we lump the two
+ // error cases together.
+ if (size < 0 || size >= kBufferSize) {
+ return String("<formatting error or buffer exceeded>");
+ } else {
+ return String(buffer, size);
+ }
+}
+
+// Converts the buffer in a StrStream to a String, converting NUL
+// bytes to "\\0" along the way.
+String StrStreamToString(StrStream* ss) {
+ const ::std::string& str = ss->str();
+ const char* const start = str.c_str();
+ const char* const end = start + str.length();
+
+ // We need to use a helper StrStream to do this transformation
+ // because String doesn't support push_back().
+ StrStream helper;
+ for (const char* ch = start; ch != end; ++ch) {
+ if (*ch == '\0') {
+ helper << "\\0"; // Replaces NUL with "\\0";
+ } else {
+ helper.put(*ch);
+ }
+ }
+
+ return String(helper.str().c_str());
+}
+
+// Appends the user-supplied message to the Google-Test-generated message.
+String AppendUserMessage(const String& gtest_msg,
+ const Message& user_msg) {
+ // Appends the user message if it's non-empty.
+ const String user_msg_string = user_msg.GetString();
+ if (user_msg_string.empty()) {
+ return gtest_msg;
+ }
+
+ Message msg;
+ msg << gtest_msg << "\n" << user_msg_string;
+
+ return msg.GetString();
+}
+
+} // namespace internal
+
+// class TestResult
+
+// Creates an empty TestResult.
+TestResult::TestResult()
+ : death_test_count_(0),
+ elapsed_time_(0) {
+}
+
+// D'tor.
+TestResult::~TestResult() {
+}
+
+// Returns the i-th test part result among all the results. i can
+// range from 0 to total_part_count() - 1. If i is not in that range,
+// aborts the program.
+const TestPartResult& TestResult::GetTestPartResult(int i) const {
+ if (i < 0 || i >= total_part_count())
+ internal::posix::Abort();
+ return test_part_results_.at(i);
+}
+
+// Returns the i-th test property. i can range from 0 to
+// test_property_count() - 1. If i is not in that range, aborts the
+// program.
+const TestProperty& TestResult::GetTestProperty(int i) const {
+ if (i < 0 || i >= test_property_count())
+ internal::posix::Abort();
+ return test_properties_.at(i);
+}
+
+// Clears the test part results.
+void TestResult::ClearTestPartResults() {
+ test_part_results_.clear();
+}
+
+// Adds a test part result to the list.
+void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
+ test_part_results_.push_back(test_part_result);
+}
+
+// Adds a test property to the list. If a property with the same key as the
+// supplied property is already represented, the value of this test_property
+// replaces the old value for that key.
+void TestResult::RecordProperty(const TestProperty& test_property) {
+ if (!ValidateTestProperty(test_property)) {
+ return;
+ }
+ internal::MutexLock lock(&test_properites_mutex_);
+ const std::vector<TestProperty>::iterator property_with_matching_key =
+ std::find_if(test_properties_.begin(), test_properties_.end(),
+ internal::TestPropertyKeyIs(test_property.key()));
+ if (property_with_matching_key == test_properties_.end()) {
+ test_properties_.push_back(test_property);
+ return;
+ }
+ property_with_matching_key->SetValue(test_property.value());
+}
+
+// Adds a failure if the key is a reserved attribute of Google Test
+// testcase tags. Returns true if the property is valid.
+bool TestResult::ValidateTestProperty(const TestProperty& test_property) {
+ internal::String key(test_property.key());
+ if (key == "name" || key == "status" || key == "time" || key == "classname") {
+ ADD_FAILURE()
+ << "Reserved key used in RecordProperty(): "
+ << key
+ << " ('name', 'status', 'time', and 'classname' are reserved by "
+ << GTEST_NAME_ << ")";
+ return false;
+ }
+ return true;
+}
+
+// Clears the object.
+void TestResult::Clear() {
+ test_part_results_.clear();
+ test_properties_.clear();
+ death_test_count_ = 0;
+ elapsed_time_ = 0;
+}
+
+// Returns true iff the test failed.
+bool TestResult::Failed() const {
+ for (int i = 0; i < total_part_count(); ++i) {
+ if (GetTestPartResult(i).failed())
+ return true;
+ }
+ return false;
+}
+
+// Returns true iff the test part fatally failed.
+static bool TestPartFatallyFailed(const TestPartResult& result) {
+ return result.fatally_failed();
+}
+
+// Returns true iff the test fatally failed.
+bool TestResult::HasFatalFailure() const {
+ return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
+}
+
+// Returns true iff the test part non-fatally failed.
+static bool TestPartNonfatallyFailed(const TestPartResult& result) {
+ return result.nonfatally_failed();
+}
+
+// Returns true iff the test has a non-fatal failure.
+bool TestResult::HasNonfatalFailure() const {
+ return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
+}
+
+// Gets the number of all test parts. This is the sum of the number
+// of successful test parts and the number of failed test parts.
+int TestResult::total_part_count() const {
+ return static_cast<int>(test_part_results_.size());
+}
+
+// Returns the number of the test properties.
+int TestResult::test_property_count() const {
+ return static_cast<int>(test_properties_.size());
+}
+
+// class Test
+
+// Creates a Test object.
+
+// The c'tor saves the values of all Google Test flags.
+Test::Test()
+ : gtest_flag_saver_(new internal::GTestFlagSaver) {
+}
+
+// The d'tor restores the values of all Google Test flags.
+Test::~Test() {
+ delete gtest_flag_saver_;
+}
+
+// Sets up the test fixture.
+//
+// A sub-class may override this.
+void Test::SetUp() {
+}
+
+// Tears down the test fixture.
+//
+// A sub-class may override this.
+void Test::TearDown() {
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, const char* value) {
+ UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value);
+}
+
+// Allows user supplied key value pairs to be recorded for later output.
+void Test::RecordProperty(const char* key, int value) {
+ Message value_message;
+ value_message << value;
+ RecordProperty(key, value_message.GetString().c_str());
+}
+
+namespace internal {
+
+void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
+ const String& message) {
+ // This function is a friend of UnitTest and as such has access to
+ // AddTestPartResult.
+ UnitTest::GetInstance()->AddTestPartResult(
+ result_type,
+ NULL, // No info about the source file where the exception occurred.
+ -1, // We have no info on which line caused the exception.
+ message,
+ String()); // No stack trace, either.
+}
+
+} // namespace internal
+
+#if GTEST_OS_WINDOWS
+// We are on Windows.
+
+// Adds an "exception thrown" fatal failure to the current test.
+static void AddExceptionThrownFailure(DWORD exception_code,
+ const char* location) {
+ Message message;
+ message << "Exception thrown with code 0x" << std::setbase(16) <<
+ exception_code << std::setbase(10) << " in " << location << ".";
+
+ internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
+ message.GetString());
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Google Test requires all tests in the same test case to use the same test
+// fixture class. This function checks if the current test has the
+// same fixture class as the first test in the current test case. If
+// yes, it returns true; otherwise it generates a Google Test failure and
+// returns false.
+bool Test::HasSameFixtureClass() {
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ const TestCase* const test_case = impl->current_test_case();
+
+ // Info about the first test in the current test case.
+ const internal::TestInfoImpl* const first_test_info =
+ test_case->test_info_list()[0]->impl();
+ const internal::TypeId first_fixture_id = first_test_info->fixture_class_id();
+ const char* const first_test_name = first_test_info->name();
+
+ // Info about the current test.
+ const internal::TestInfoImpl* const this_test_info =
+ impl->current_test_info()->impl();
+ const internal::TypeId this_fixture_id = this_test_info->fixture_class_id();
+ const char* const this_test_name = this_test_info->name();
+
+ if (this_fixture_id != first_fixture_id) {
+ // Is the first test defined using TEST?
+ const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
+ // Is this test defined using TEST?
+ const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
+
+ if (first_is_TEST || this_is_TEST) {
+ // The user mixed TEST and TEST_F in this test case - we'll tell
+ // him/her how to fix it.
+
+ // Gets the name of the TEST and the name of the TEST_F. Note
+ // that first_is_TEST and this_is_TEST cannot both be true, as
+ // the fixture IDs are different for the two tests.
+ const char* const TEST_name =
+ first_is_TEST ? first_test_name : this_test_name;
+ const char* const TEST_F_name =
+ first_is_TEST ? this_test_name : first_test_name;
+
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class, so mixing TEST_F and TEST in the same test case is\n"
+ << "illegal. In test case " << this_test_info->test_case_name()
+ << ",\n"
+ << "test " << TEST_F_name << " is defined using TEST_F but\n"
+ << "test " << TEST_name << " is defined using TEST. You probably\n"
+ << "want to change the TEST to TEST_F or move it to another test\n"
+ << "case.";
+ } else {
+ // The user defined two fixture classes with the same name in
+ // two namespaces - we'll tell him/her how to fix it.
+ ADD_FAILURE()
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case "
+ << this_test_info->test_case_name() << ",\n"
+ << "you defined test " << first_test_name
+ << " and test " << this_test_name << "\n"
+ << "using two different test fixture classes. This can happen if\n"
+ << "the two classes are from different namespaces or translation\n"
+ << "units and have the same name. You should probably rename one\n"
+ << "of the classes to put the tests into different test cases.";
+ }
+ return false;
+ }
+
+ return true;
+}
+
+// Runs the test and updates the test result.
+void Test::Run() {
+ if (!HasSameFixtureClass()) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+#if GTEST_HAS_SEH
+ // Catch SEH-style exceptions.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ SetUp();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "SetUp()");
+ }
+
+ // We will run the test only if SetUp() had no fatal failure.
+ if (!HasFatalFailure()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ TestBody();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "the test body");
+ }
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ __try {
+ TearDown();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(), "TearDown()");
+ }
+
+#else // We are on a compiler or platform that doesn't support SEH.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ SetUp();
+
+ // We will run the test only if SetUp() was successful.
+ if (!HasFatalFailure()) {
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ TestBody();
+ }
+
+ // However, we want to clean up as much as possible. Hence we will
+ // always call TearDown(), even if SetUp() or the test body has
+ // failed.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ TearDown();
+#endif // GTEST_HAS_SEH
+}
+
+
+// Returns true iff the current test has a fatal failure.
+bool Test::HasFatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
+}
+
+// Returns true iff the current test has a non-fatal failure.
+bool Test::HasNonfatalFailure() {
+ return internal::GetUnitTestImpl()->current_test_result()->
+ HasNonfatalFailure();
+}
+
+// class TestInfo
+
+// Constructs a TestInfo object. It assumes ownership of the test factory
+// object via impl_.
+TestInfo::TestInfo(const char* a_test_case_name,
+ const char* a_name,
+ const char* a_test_case_comment,
+ const char* a_comment,
+ internal::TypeId fixture_class_id,
+ internal::TestFactoryBase* factory) {
+ impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name,
+ a_test_case_comment, a_comment,
+ fixture_class_id, factory);
+}
+
+// Destructs a TestInfo object.
+TestInfo::~TestInfo() {
+ delete impl_;
+}
+
+namespace internal {
+
+// Creates a new TestInfo object and registers it with Google Test;
+// returns the created object.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// name: name of the test
+// test_case_comment: a comment on the test case that will be included in
+// the test output
+// comment: a comment on the test that will be included in the
+// test output
+// fixture_class_id: ID of the test fixture class
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+// factory: pointer to the factory that creates a test object.
+// The newly created TestInfo instance will assume
+// ownership of the factory object.
+TestInfo* MakeAndRegisterTestInfo(
+ const char* test_case_name, const char* name,
+ const char* test_case_comment, const char* comment,
+ TypeId fixture_class_id,
+ SetUpTestCaseFunc set_up_tc,
+ TearDownTestCaseFunc tear_down_tc,
+ TestFactoryBase* factory) {
+ TestInfo* const test_info =
+ new TestInfo(test_case_name, name, test_case_comment, comment,
+ fixture_class_id, factory);
+ GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
+ return test_info;
+}
+
+#if GTEST_HAS_PARAM_TEST
+void ReportInvalidTestCaseType(const char* test_case_name,
+ const char* file, int line) {
+ Message errors;
+ errors
+ << "Attempted redefinition of test case " << test_case_name << ".\n"
+ << "All tests in the same test case must use the same test fixture\n"
+ << "class. However, in test case " << test_case_name << ", you tried\n"
+ << "to define a test using a fixture class different from the one\n"
+ << "used earlier. This can happen if the two fixture classes are\n"
+ << "from different namespaces and have the same name. You should\n"
+ << "probably rename one of the classes to put the tests into different\n"
+ << "test cases.";
+
+ fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+ errors.GetString().c_str());
+}
+#endif // GTEST_HAS_PARAM_TEST
+
+} // namespace internal
+
+// Returns the test case name.
+const char* TestInfo::test_case_name() const {
+ return impl_->test_case_name();
+}
+
+// Returns the test name.
+const char* TestInfo::name() const {
+ return impl_->name();
+}
+
+// Returns the test case comment.
+const char* TestInfo::test_case_comment() const {
+ return impl_->test_case_comment();
+}
+
+// Returns the test comment.
+const char* TestInfo::comment() const {
+ return impl_->comment();
+}
+
+// Returns true if this test should run.
+bool TestInfo::should_run() const { return impl_->should_run(); }
+
+// Returns true if this test matches the user-specified filter.
+bool TestInfo::matches_filter() const { return impl_->matches_filter(); }
+
+// Returns the result of the test.
+const TestResult* TestInfo::result() const { return impl_->result(); }
+
+// Increments the number of death tests encountered in this test so
+// far.
+int TestInfo::increment_death_test_count() {
+ return impl_->result()->increment_death_test_count();
+}
+
+namespace {
+
+// A predicate that checks the test name of a TestInfo against a known
+// value.
+//
+// This is used for implementation of the TestCase class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestNameIs is copyable.
+class TestNameIs {
+ public:
+ // Constructor.
+ //
+ // TestNameIs has NO default constructor.
+ explicit TestNameIs(const char* name)
+ : name_(name) {}
+
+ // Returns true iff the test name of test_info matches name_.
+ bool operator()(const TestInfo * test_info) const {
+ return test_info && internal::String(test_info->name()).Compare(name_) == 0;
+ }
+
+ private:
+ internal::String name_;
+};
+
+} // namespace
+
+namespace internal {
+
+// This method expands all parameterized tests registered with macros TEST_P
+// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
+// This will be done just once during the program runtime.
+void UnitTestImpl::RegisterParameterizedTests() {
+#if GTEST_HAS_PARAM_TEST
+ if (!parameterized_tests_registered_) {
+ parameterized_test_registry_.RegisterTests();
+ parameterized_tests_registered_ = true;
+ }
+#endif
+}
+
+// Creates the test object, runs it, records its result, and then
+// deletes it.
+void TestInfoImpl::Run() {
+ if (!should_run_) return;
+
+ // Tells UnitTest where to store test result.
+ UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_info(parent_);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ // Notifies the unit test event listeners that a test is about to start.
+ repeater->OnTestStart(*parent_);
+
+ const TimeInMillis start = GetTimeInMillis();
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+#if GTEST_HAS_SEH
+ // Catch SEH-style exceptions.
+ Test* test = NULL;
+
+ __try {
+ // Creates the test object.
+ test = factory_->CreateTest();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ AddExceptionThrownFailure(GetExceptionCode(),
+ "the test fixture's constructor");
+ return;
+ }
+#else // We are on a compiler or platform that doesn't support SEH.
+
+ // TODO(wan): If test->Run() throws, test won't be deleted. This is
+ // not a problem now as we don't use exceptions. If we were to
+ // enable exceptions, we should revise the following to be
+ // exception-safe.
+
+ // Creates the test object.
+ Test* test = factory_->CreateTest();
+#endif // GTEST_HAS_SEH
+
+ // Runs the test only if the constructor of the test fixture didn't
+ // generate a fatal failure.
+ if (!Test::HasFatalFailure()) {
+ test->Run();
+ }
+
+ // Deletes the test object.
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ delete test;
+ test = NULL;
+
+ result_.set_elapsed_time(GetTimeInMillis() - start);
+
+ // Notifies the unit test event listener that a test has just finished.
+ repeater->OnTestEnd(*parent_);
+
+ // Tells UnitTest to stop associating assertion results to this
+ // test.
+ impl->set_current_test_info(NULL);
+}
+
+} // namespace internal
+
+// class TestCase
+
+// Gets the number of successful tests in this test case.
+int TestCase::successful_test_count() const {
+ return CountIf(test_info_list_, TestPassed);
+}
+
+// Gets the number of failed tests in this test case.
+int TestCase::failed_test_count() const {
+ return CountIf(test_info_list_, TestFailed);
+}
+
+int TestCase::disabled_test_count() const {
+ return CountIf(test_info_list_, TestDisabled);
+}
+
+// Get the number of tests in this test case that should run.
+int TestCase::test_to_run_count() const {
+ return CountIf(test_info_list_, ShouldRunTest);
+}
+
+// Gets the number of all tests.
+int TestCase::total_test_count() const {
+ return static_cast<int>(test_info_list_.size());
+}
+
+// Creates a TestCase with the given name.
+//
+// Arguments:
+//
+// name: name of the test case
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase::TestCase(const char* a_name, const char* a_comment,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc)
+ : name_(a_name),
+ comment_(a_comment),
+ set_up_tc_(set_up_tc),
+ tear_down_tc_(tear_down_tc),
+ should_run_(false),
+ elapsed_time_(0) {
+}
+
+// Destructor of TestCase.
+TestCase::~TestCase() {
+ // Deletes every Test in the collection.
+ ForEach(test_info_list_, internal::Delete<TestInfo>);
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+const TestInfo* TestCase::GetTestInfo(int i) const {
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Returns the i-th test among all the tests. i can range from 0 to
+// total_test_count() - 1. If i is not in that range, returns NULL.
+TestInfo* TestCase::GetMutableTestInfo(int i) {
+ const int index = GetElementOr(test_indices_, i, -1);
+ return index < 0 ? NULL : test_info_list_[index];
+}
+
+// Adds a test to this test case. Will delete the test upon
+// destruction of the TestCase object.
+void TestCase::AddTestInfo(TestInfo * test_info) {
+ test_info_list_.push_back(test_info);
+ test_indices_.push_back(static_cast<int>(test_indices_.size()));
+}
+
+// Runs every test in this TestCase.
+void TestCase::Run() {
+ if (!should_run_) return;
+
+ internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+ impl->set_current_test_case(this);
+
+ TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
+
+ repeater->OnTestCaseStart(*this);
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ set_up_tc_();
+
+ const internal::TimeInMillis start = internal::GetTimeInMillis();
+ for (int i = 0; i < total_test_count(); i++) {
+ GetMutableTestInfo(i)->impl()->Run();
+ }
+ elapsed_time_ = internal::GetTimeInMillis() - start;
+
+ impl->os_stack_trace_getter()->UponLeavingGTest();
+ tear_down_tc_();
+ repeater->OnTestCaseEnd(*this);
+ impl->set_current_test_case(NULL);
+}
+
+// Clears the results of all tests in this test case.
+void TestCase::ClearResult() {
+ ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult);
+}
+
+// Returns true iff test passed.
+bool TestCase::TestPassed(const TestInfo * test_info) {
+ const internal::TestInfoImpl* const impl = test_info->impl();
+ return impl->should_run() && impl->result()->Passed();
+}
+
+// Returns true iff test failed.
+bool TestCase::TestFailed(const TestInfo * test_info) {
+ const internal::TestInfoImpl* const impl = test_info->impl();
+ return impl->should_run() && impl->result()->Failed();
+}
+
+// Returns true iff test is disabled.
+bool TestCase::TestDisabled(const TestInfo * test_info) {
+ return test_info->impl()->is_disabled();
+}
+
+// Returns true if the given test should run.
+bool TestCase::ShouldRunTest(const TestInfo *test_info) {
+ return test_info->impl()->should_run();
+}
+
+// Shuffles the tests in this test case.
+void TestCase::ShuffleTests(internal::Random* random) {
+ Shuffle(random, &test_indices_);
+}
+
+// Restores the test order to before the first shuffle.
+void TestCase::UnshuffleTests() {
+ for (size_t i = 0; i < test_indices_.size(); i++) {
+ test_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// Formats a countable noun. Depending on its quantity, either the
+// singular form or the plural form is used. e.g.
+//
+// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
+// FormatCountableNoun(5, "book", "books") returns "5 books".
+static internal::String FormatCountableNoun(int count,
+ const char * singular_form,
+ const char * plural_form) {
+ return internal::String::Format("%d %s", count,
+ count == 1 ? singular_form : plural_form);
+}
+
+// Formats the count of tests.
+static internal::String FormatTestCount(int test_count) {
+ return FormatCountableNoun(test_count, "test", "tests");
+}
+
+// Formats the count of test cases.
+static internal::String FormatTestCaseCount(int test_case_count) {
+ return FormatCountableNoun(test_case_count, "test case", "test cases");
+}
+
+// Converts a TestPartResult::Type enum to human-friendly string
+// representation. Both kNonFatalFailure and kFatalFailure are translated
+// to "Failure", as the user usually doesn't care about the difference
+// between the two when viewing the test result.
+static const char * TestPartResultTypeToString(TestPartResult::Type type) {
+ switch (type) {
+ case TestPartResult::kSuccess:
+ return "Success";
+
+ case TestPartResult::kNonFatalFailure:
+ case TestPartResult::kFatalFailure:
+#ifdef _MSC_VER
+ return "error: ";
+#else
+ return "Failure\n";
+#endif
+ }
+
+ return "Unknown result type";
+}
+
+// Prints a TestPartResult to a String.
+static internal::String PrintTestPartResultToString(
+ const TestPartResult& test_part_result) {
+ return (Message()
+ << internal::FormatFileLocation(test_part_result.file_name(),
+ test_part_result.line_number())
+ << " " << TestPartResultTypeToString(test_part_result.type())
+ << test_part_result.message()).GetString();
+}
+
+// Prints a TestPartResult.
+static void PrintTestPartResult(const TestPartResult& test_part_result) {
+ const internal::String& result =
+ PrintTestPartResultToString(test_part_result);
+ printf("%s\n", result.c_str());
+ fflush(stdout);
+ // If the test program runs in Visual Studio or a debugger, the
+ // following statements add the test part result message to the Output
+ // window such that the user can double-click on it to jump to the
+ // corresponding source code location; otherwise they do nothing.
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ // We don't call OutputDebugString*() on Windows Mobile, as printing
+ // to stdout is done by OutputDebugString() there already - we don't
+ // want the same message printed twice.
+ ::OutputDebugStringA(result.c_str());
+ ::OutputDebugStringA("\n");
+#endif
+}
+
+// class PrettyUnitTestResultPrinter
+
+namespace internal {
+
+enum GTestColor {
+ COLOR_DEFAULT,
+ COLOR_RED,
+ COLOR_GREEN,
+ COLOR_YELLOW
+};
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GTestColor color) {
+ switch (color) {
+ case COLOR_RED: return FOREGROUND_RED;
+ case COLOR_GREEN: return FOREGROUND_GREEN;
+ case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+ default: return 0;
+ }
+}
+
+#else
+
+// Returns the ANSI color code for the given color. COLOR_DEFAULT is
+// an invalid input.
+const char* GetAnsiColorCode(GTestColor color) {
+ switch (color) {
+ case COLOR_RED: return "1";
+ case COLOR_GREEN: return "2";
+ case COLOR_YELLOW: return "3";
+ default: return NULL;
+ };
+}
+
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+
+// Returns true iff Google Test should use colors in the output.
+bool ShouldUseColor(bool stdout_is_tty) {
+ const char* const gtest_color = GTEST_FLAG(color).c_str();
+
+ if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
+#if GTEST_OS_WINDOWS
+ // On Windows the TERM variable is usually not set, but the
+ // console there does support colors.
+ return stdout_is_tty;
+#else
+ // On non-Windows platforms, we rely on the TERM variable.
+ const char* const term = posix::GetEnv("TERM");
+ const bool term_supports_color =
+ String::CStringEquals(term, "xterm") ||
+ String::CStringEquals(term, "xterm-color") ||
+ String::CStringEquals(term, "xterm-256color") ||
+ String::CStringEquals(term, "linux") ||
+ String::CStringEquals(term, "cygwin");
+ return stdout_is_tty && term_supports_color;
+#endif // GTEST_OS_WINDOWS
+ }
+
+ return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
+ String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
+ String::CStringEquals(gtest_color, "1");
+ // We take "yes", "true", "t", and "1" as meaning "yes". If the
+ // value is neither one of these nor "auto", we treat it as "no" to
+ // be conservative.
+}
+
+// Helpers for printing colored strings to stdout. Note that on Windows, we
+// cannot simply emit special characters and have the terminal change colors.
+// This routine must actually emit the characters rather than return a string
+// that would be colored when printed, as can be done on Linux.
+void ColoredPrintf(GTestColor color, const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+ const bool use_color = false;
+#else
+ static const bool in_color_mode =
+ ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
+ const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
+#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
+ // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
+
+ if (!use_color) {
+ vprintf(fmt, args);
+ va_end(args);
+ return;
+ }
+
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ // Gets the current text color.
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+ GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
+ const WORD old_color_attrs = buffer_info.wAttributes;
+
+ // We need to flush the stream buffers into the console before each
+ // SetConsoleTextAttribute call lest it affect the text that is already
+ // printed but has not yet reached the console.
+ fflush(stdout);
+ SetConsoleTextAttribute(stdout_handle,
+ GetColorAttribute(color) | FOREGROUND_INTENSITY);
+ vprintf(fmt, args);
+
+ fflush(stdout);
+ // Restores the text color.
+ SetConsoleTextAttribute(stdout_handle, old_color_attrs);
+#else
+ printf("\033[0;3%sm", GetAnsiColorCode(color));
+ vprintf(fmt, args);
+ printf("\033[m"); // Resets the terminal to default.
+#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
+ va_end(args);
+}
+
+// This class implements the TestEventListener interface.
+//
+// Class PrettyUnitTestResultPrinter is copyable.
+class PrettyUnitTestResultPrinter : public TestEventListener {
+ public:
+ PrettyUnitTestResultPrinter() {}
+ static void PrintTestName(const char * test_case, const char * test) {
+ printf("%s.%s", test_case, test);
+ }
+
+ // The following methods override what's in the TestEventListener class.
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestCaseStart(const TestCase& test_case);
+ virtual void OnTestStart(const TestInfo& test_info);
+ virtual void OnTestPartResult(const TestPartResult& result);
+ virtual void OnTestEnd(const TestInfo& test_info);
+ virtual void OnTestCaseEnd(const TestCase& test_case);
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+
+ private:
+ static void PrintFailedTests(const UnitTest& unit_test);
+
+ internal::String test_case_name_;
+};
+
+ // Fired before each iteration of tests starts.
+void PrettyUnitTestResultPrinter::OnTestIterationStart(
+ const UnitTest& unit_test, int iteration) {
+ if (GTEST_FLAG(repeat) != 1)
+ printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);
+
+ const char* const filter = GTEST_FLAG(filter).c_str();
+
+ // Prints the filter if it's not *. This reminds the user that some
+ // tests may be skipped.
+ if (!internal::String::CStringEquals(filter, kUniversalFilter)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: %s filter = %s\n", GTEST_NAME_, filter);
+ }
+
+ if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: This is test shard %s of %s.\n",
+ internal::posix::GetEnv(kTestShardIndex),
+ internal::posix::GetEnv(kTestTotalShards));
+ }
+
+ if (GTEST_FLAG(shuffle)) {
+ ColoredPrintf(COLOR_YELLOW,
+ "Note: Randomizing tests' orders with a seed of %d .\n",
+ unit_test.random_seed());
+ }
+
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("Running %s from %s.\n",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
+ const UnitTest& /*unit_test*/) {
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment set-up.\n");
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
+ test_case_name_ = test_case.name();
+ const internal::String counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s", counts.c_str(), test_case_name_.c_str());
+ if (test_case.comment()[0] == '\0') {
+ printf("\n");
+ } else {
+ printf(", where %s\n", test_case.comment());
+ }
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
+ ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
+ PrintTestName(test_case_name_.c_str(), test_info.name());
+ if (test_info.comment()[0] == '\0') {
+ printf("\n");
+ } else {
+ printf(", where %s\n", test_info.comment());
+ }
+ fflush(stdout);
+}
+
+// Called after an assertion failure.
+void PrettyUnitTestResultPrinter::OnTestPartResult(
+ const TestPartResult& result) {
+ // If the test part succeeded, we don't need to do anything.
+ if (result.type() == TestPartResult::kSuccess)
+ return;
+
+ // Print failure message from the assertion (e.g. expected this and got that).
+ PrintTestPartResult(result);
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
+ if (test_info.result()->Passed()) {
+ ColoredPrintf(COLOR_GREEN, "[ OK ] ");
+ } else {
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ }
+ PrintTestName(test_case_name_.c_str(), test_info.name());
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms)\n", internal::StreamableToString(
+ test_info.result()->elapsed_time()).c_str());
+ } else {
+ printf("\n");
+ }
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
+ if (!GTEST_FLAG(print_time)) return;
+
+ test_case_name_ = test_case.name();
+ const internal::String counts =
+ FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("%s from %s (%s ms total)\n\n",
+ counts.c_str(), test_case_name_.c_str(),
+ internal::StreamableToString(test_case.elapsed_time()).c_str());
+ fflush(stdout);
+}
+
+void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
+ const UnitTest& /*unit_test*/) {
+ ColoredPrintf(COLOR_GREEN, "[----------] ");
+ printf("Global test environment tear-down\n");
+ fflush(stdout);
+}
+
+// Internal helper for printing the list of failed tests.
+void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
+ const int failed_test_count = unit_test.failed_test_count();
+ if (failed_test_count == 0) {
+ return;
+ }
+
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ const TestCase& test_case = *unit_test.GetTestCase(i);
+ if (!test_case.should_run() || (test_case.failed_test_count() == 0)) {
+ continue;
+ }
+ for (int j = 0; j < test_case.total_test_count(); ++j) {
+ const TestInfo& test_info = *test_case.GetTestInfo(j);
+ if (!test_info.should_run() || test_info.result()->Passed()) {
+ continue;
+ }
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s.%s", test_case.name(), test_info.name());
+ if (test_case.comment()[0] != '\0' ||
+ test_info.comment()[0] != '\0') {
+ printf(", where %s", test_case.comment());
+ if (test_case.comment()[0] != '\0' &&
+ test_info.comment()[0] != '\0') {
+ printf(" and ");
+ }
+ }
+ printf("%s\n", test_info.comment());
+ }
+ }
+}
+
+ void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ ColoredPrintf(COLOR_GREEN, "[==========] ");
+ printf("%s from %s ran.",
+ FormatTestCount(unit_test.test_to_run_count()).c_str(),
+ FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
+ if (GTEST_FLAG(print_time)) {
+ printf(" (%s ms total)",
+ internal::StreamableToString(unit_test.elapsed_time()).c_str());
+ }
+ printf("\n");
+ ColoredPrintf(COLOR_GREEN, "[ PASSED ] ");
+ printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
+
+ int num_failures = unit_test.failed_test_count();
+ if (!unit_test.Passed()) {
+ const int failed_test_count = unit_test.failed_test_count();
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
+ PrintFailedTests(unit_test);
+ printf("\n%2d FAILED %s\n", num_failures,
+ num_failures == 1 ? "TEST" : "TESTS");
+ }
+
+ int num_disabled = unit_test.disabled_test_count();
+ if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
+ if (!num_failures) {
+ printf("\n"); // Add a spacer if no FAILURE banner is displayed.
+ }
+ ColoredPrintf(COLOR_YELLOW,
+ " YOU HAVE %d DISABLED %s\n\n",
+ num_disabled,
+ num_disabled == 1 ? "TEST" : "TESTS");
+ }
+ // Ensure that Google Test output is printed before, e.g., heapchecker output.
+ fflush(stdout);
+}
+
+// End PrettyUnitTestResultPrinter
+
+// class TestEventRepeater
+//
+// This class forwards events to other event listeners.
+class TestEventRepeater : public TestEventListener {
+ public:
+ TestEventRepeater() : forwarding_enabled_(true) {}
+ virtual ~TestEventRepeater();
+ void Append(TestEventListener *listener);
+ TestEventListener* Release(TestEventListener* listener);
+
+ // Controls whether events will be forwarded to listeners_. Set to false
+ // in death test child processes.
+ bool forwarding_enabled() const { return forwarding_enabled_; }
+ void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }
+
+ virtual void OnTestProgramStart(const UnitTest& unit_test);
+ virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
+ virtual void OnTestCaseStart(const TestCase& test_case);
+ virtual void OnTestStart(const TestInfo& test_info);
+ virtual void OnTestPartResult(const TestPartResult& result);
+ virtual void OnTestEnd(const TestInfo& test_info);
+ virtual void OnTestCaseEnd(const TestCase& test_case);
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+ virtual void OnTestProgramEnd(const UnitTest& unit_test);
+
+ private:
+ // Controls whether events will be forwarded to listeners_. Set to false
+ // in death test child processes.
+ bool forwarding_enabled_;
+ // The list of listeners that receive events.
+ std::vector<TestEventListener*> listeners_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
+};
+
+TestEventRepeater::~TestEventRepeater() {
+ ForEach(listeners_, Delete<TestEventListener>);
+}
+
+void TestEventRepeater::Append(TestEventListener *listener) {
+ listeners_.push_back(listener);
+}
+
+// TODO(vladl@google.com): Factor the search functionality into Vector::Find.
+TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
+ for (size_t i = 0; i < listeners_.size(); ++i) {
+ if (listeners_[i] == listener) {
+ listeners_.erase(listeners_.begin() + i);
+ return listener;
+ }
+ }
+
+ return NULL;
+}
+
+// Since most methods are very similar, use macros to reduce boilerplate.
+// This defines a member that forwards the call to all listeners.
+#define GTEST_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (size_t i = 0; i < listeners_.size(); i++) { \
+ listeners_[i]->Name(parameter); \
+ } \
+ } \
+}
+// This defines a member that forwards the call to all listeners in reverse
+// order.
+#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
+void TestEventRepeater::Name(const Type& parameter) { \
+ if (forwarding_enabled_) { \
+ for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
+ listeners_[i]->Name(parameter); \
+ } \
+ } \
+}
+
+GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
+GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
+GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
+GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
+GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
+GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)
+
+#undef GTEST_REPEATER_METHOD_
+#undef GTEST_REVERSE_REPEATER_METHOD_
+
+void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
+ int iteration) {
+ if (forwarding_enabled_) {
+ for (size_t i = 0; i < listeners_.size(); i++) {
+ listeners_[i]->OnTestIterationStart(unit_test, iteration);
+ }
+ }
+}
+
+void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration) {
+ if (forwarding_enabled_) {
+ for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
+ listeners_[i]->OnTestIterationEnd(unit_test, iteration);
+ }
+ }
+}
+
+// End TestEventRepeater
+
+// This class generates an XML output file.
+class XmlUnitTestResultPrinter : public EmptyTestEventListener {
+ public:
+ explicit XmlUnitTestResultPrinter(const char* output_file);
+
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+
+ private:
+ // Is c a whitespace character that is normalized to a space character
+ // when it appears in an XML attribute value?
+ static bool IsNormalizableWhitespace(char c) {
+ return c == 0x9 || c == 0xA || c == 0xD;
+ }
+
+ // May c appear in a well-formed XML document?
+ static bool IsValidXmlCharacter(char c) {
+ return IsNormalizableWhitespace(c) || c >= 0x20;
+ }
+
+ // Returns an XML-escaped copy of the input string str. If
+ // is_attribute is true, the text is meant to appear as an attribute
+ // value, and normalizable whitespace is preserved by replacing it
+ // with character references.
+ static String EscapeXml(const char* str, bool is_attribute);
+
+ // Returns the given string with all characters invalid in XML removed.
+ static String RemoveInvalidXmlCharacters(const char* str);
+
+ // Convenience wrapper around EscapeXml when str is an attribute value.
+ static String EscapeXmlAttribute(const char* str) {
+ return EscapeXml(str, true);
+ }
+
+ // Convenience wrapper around EscapeXml when str is not an attribute value.
+ static String EscapeXmlText(const char* str) { return EscapeXml(str, false); }
+
+ // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+ static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
+
+ // Streams an XML representation of a TestInfo object.
+ static void OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_case_name,
+ const TestInfo& test_info);
+
+ // Prints an XML representation of a TestCase object
+ static void PrintXmlTestCase(FILE* out, const TestCase& test_case);
+
+ // Prints an XML summary of unit_test to output stream out.
+ static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test);
+
+ // Produces a string representing the test properties in a result as space
+ // delimited XML attributes based on the property key="value" pairs.
+ // When the String is not empty, it includes a space at the beginning,
+ // to delimit this attribute from prior attributes.
+ static String TestPropertiesAsXmlAttributes(const TestResult& result);
+
+ // The output file.
+ const String output_file_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
+};
+
+// Creates a new XmlUnitTestResultPrinter.
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
+ : output_file_(output_file) {
+ if (output_file_.c_str() == NULL || output_file_.empty()) {
+ fprintf(stderr, "XML output file may not be null\n");
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+}
+
+// Called after the unit test ends.
+void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
+ int /*iteration*/) {
+ FILE* xmlout = NULL;
+ FilePath output_file(output_file_);
+ FilePath output_dir(output_file.RemoveFileName());
+
+ if (output_dir.CreateDirectoriesRecursively()) {
+ xmlout = posix::FOpen(output_file_.c_str(), "w");
+ }
+ if (xmlout == NULL) {
+ // TODO(wan): report the reason of the failure.
+ //
+ // We don't do it for now as:
+ //
+ // 1. There is no urgent need for it.
+ // 2. It's a bit involved to make the errno variable thread-safe on
+ // all three operating systems (Linux, Windows, and Mac OS).
+ // 3. To interpret the meaning of errno in a thread-safe way,
+ // we need the strerror_r() function, which is not available on
+ // Windows.
+ fprintf(stderr,
+ "Unable to open file \"%s\"\n",
+ output_file_.c_str());
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+ PrintXmlUnitTest(xmlout, unit_test);
+ fclose(xmlout);
+}
+
+// Returns an XML-escaped copy of the input string str. If is_attribute
+// is true, the text is meant to appear as an attribute value, and
+// normalizable whitespace is preserved by replacing it with character
+// references.
+//
+// Invalid XML characters in str, if any, are stripped from the output.
+// It is expected that most, if not all, of the text processed by this
+// module will consist of ordinary English text.
+// If this module is ever modified to produce version 1.1 XML output,
+// most invalid characters can be retained using character references.
+// TODO(wan): It might be nice to have a minimally invasive, human-readable
+// escaping scheme for invalid characters, rather than dropping them.
+String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) {
+ Message m;
+
+ if (str != NULL) {
+ for (const char* src = str; *src; ++src) {
+ switch (*src) {
+ case '<':
+ m << "&lt;";
+ break;
+ case '>':
+ m << "&gt;";
+ break;
+ case '&':
+ m << "&amp;";
+ break;
+ case '\'':
+ if (is_attribute)
+ m << "&apos;";
+ else
+ m << '\'';
+ break;
+ case '"':
+ if (is_attribute)
+ m << "&quot;";
+ else
+ m << '"';
+ break;
+ default:
+ if (IsValidXmlCharacter(*src)) {
+ if (is_attribute && IsNormalizableWhitespace(*src))
+ m << String::Format("&#x%02X;", unsigned(*src));
+ else
+ m << *src;
+ }
+ break;
+ }
+ }
+ }
+
+ return m.GetString();
+}
+
+// Returns the given string with all characters invalid in XML removed.
+// Currently invalid characters are dropped from the string. An
+// alternative is to replace them with certain characters such as . or ?.
+String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) {
+ char* const output = new char[strlen(str) + 1];
+ char* appender = output;
+ for (char ch = *str; ch != '\0'; ch = *++str)
+ if (IsValidXmlCharacter(ch))
+ *appender++ = ch;
+ *appender = '\0';
+
+ String ret_value(output);
+ delete[] output;
+ return ret_value;
+}
+
+// The following routines generate an XML representation of a UnitTest
+// object.
+//
+// This is how Google Test concepts map to the DTD:
+//
+// <testsuites name="AllTests"> <-- corresponds to a UnitTest object
+// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
+// <testcase name="test-name"> <-- corresponds to a TestInfo object
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <failure message="...">...</failure>
+// <-- individual assertion failures
+// </testcase>
+// </testsuite>
+// </testsuites>
+
+// Formats the given time in milliseconds as seconds.
+std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
+ ::std::stringstream ss;
+ ss << ms/1000.0;
+ return ss.str();
+}
+
+// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
+void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
+ const char* data) {
+ const char* segment = data;
+ *stream << "<![CDATA[";
+ for (;;) {
+ const char* const next_segment = strstr(segment, "]]>");
+ if (next_segment != NULL) {
+ stream->write(
+ segment, static_cast<std::streamsize>(next_segment - segment));
+ *stream << "]]>]]&gt;<![CDATA[";
+ segment = next_segment + strlen("]]>");
+ } else {
+ *stream << segment;
+ break;
+ }
+ }
+ *stream << "]]>";
+}
+
+// Prints an XML representation of a TestInfo object.
+// TODO(wan): There is also value in printing properties with the plain printer.
+void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
+ const char* test_case_name,
+ const TestInfo& test_info) {
+ const TestResult& result = *test_info.result();
+ *stream << " <testcase name=\""
+ << EscapeXmlAttribute(test_info.name()).c_str()
+ << "\" status=\""
+ << (test_info.should_run() ? "run" : "notrun")
+ << "\" time=\""
+ << FormatTimeInMillisAsSeconds(result.elapsed_time())
+ << "\" classname=\"" << EscapeXmlAttribute(test_case_name).c_str()
+ << "\"" << TestPropertiesAsXmlAttributes(result).c_str();
+
+ int failures = 0;
+ for (int i = 0; i < result.total_part_count(); ++i) {
+ const TestPartResult& part = result.GetTestPartResult(i);
+ if (part.failed()) {
+ if (++failures == 1)
+ *stream << ">\n";
+ *stream << " <failure message=\""
+ << EscapeXmlAttribute(part.summary()).c_str()
+ << "\" type=\"\">";
+ const String message = RemoveInvalidXmlCharacters(String::Format(
+ "%s:%d\n%s",
+ part.file_name(), part.line_number(),
+ part.message()).c_str());
+ OutputXmlCDataSection(stream, message.c_str());
+ *stream << "</failure>\n";
+ }
+ }
+
+ if (failures == 0)
+ *stream << " />\n";
+ else
+ *stream << " </testcase>\n";
+}
+
+// Prints an XML representation of a TestCase object
+void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,
+ const TestCase& test_case) {
+ fprintf(out,
+ " <testsuite name=\"%s\" tests=\"%d\" failures=\"%d\" "
+ "disabled=\"%d\" ",
+ EscapeXmlAttribute(test_case.name()).c_str(),
+ test_case.total_test_count(),
+ test_case.failed_test_count(),
+ test_case.disabled_test_count());
+ fprintf(out,
+ "errors=\"0\" time=\"%s\">\n",
+ FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str());
+ for (int i = 0; i < test_case.total_test_count(); ++i) {
+ StrStream stream;
+ OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i));
+ fprintf(out, "%s", StrStreamToString(&stream).c_str());
+ }
+ fprintf(out, " </testsuite>\n");
+}
+
+// Prints an XML summary of unit_test to output stream out.
+void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
+ const UnitTest& unit_test) {
+ fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ fprintf(out,
+ "<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
+ "errors=\"0\" time=\"%s\" ",
+ unit_test.total_test_count(),
+ unit_test.failed_test_count(),
+ unit_test.disabled_test_count(),
+ FormatTimeInMillisAsSeconds(unit_test.elapsed_time()).c_str());
+ if (GTEST_FLAG(shuffle)) {
+ fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed());
+ }
+ fprintf(out, "name=\"AllTests\">\n");
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i)
+ PrintXmlTestCase(out, *unit_test.GetTestCase(i));
+ fprintf(out, "</testsuites>\n");
+}
+
+// Produces a string representing the test properties in a result as space
+// delimited XML attributes based on the property key="value" pairs.
+String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
+ const TestResult& result) {
+ Message attributes;
+ for (int i = 0; i < result.test_property_count(); ++i) {
+ const TestProperty& property = result.GetTestProperty(i);
+ attributes << " " << property.key() << "="
+ << "\"" << EscapeXmlAttribute(property.value()) << "\"";
+ }
+ return attributes.GetString();
+}
+
+// End XmlUnitTestResultPrinter
+
+// Class ScopedTrace
+
+// Pushes the given source file location and message onto a per-thread
+// trace stack maintained by Google Test.
+// L < UnitTest::mutex_
+ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) {
+ TraceInfo trace;
+ trace.file = file;
+ trace.line = line;
+ trace.message = message.GetString();
+
+ UnitTest::GetInstance()->PushGTestTrace(trace);
+}
+
+// Pops the info pushed by the c'tor.
+// L < UnitTest::mutex_
+ScopedTrace::~ScopedTrace() {
+ UnitTest::GetInstance()->PopGTestTrace();
+}
+
+
+// class OsStackTraceGetter
+
+// Returns the current OS stack trace as a String. Parameters:
+//
+// max_depth - the maximum number of stack frames to be included
+// in the trace.
+// skip_count - the number of top frames to be skipped; doesn't count
+// against max_depth.
+//
+// L < mutex_
+// We use "L < mutex_" to denote that the function may acquire mutex_.
+String OsStackTraceGetter::CurrentStackTrace(int, int) {
+ return String("");
+}
+
+// L < mutex_
+void OsStackTraceGetter::UponLeavingGTest() {
+}
+
+const char* const
+OsStackTraceGetter::kElidedFramesMarker =
+ "... " GTEST_NAME_ " internal frames ...";
+
+} // namespace internal
+
+// class TestEventListeners
+
+TestEventListeners::TestEventListeners()
+ : repeater_(new internal::TestEventRepeater()),
+ default_result_printer_(NULL),
+ default_xml_generator_(NULL) {
+}
+
+TestEventListeners::~TestEventListeners() { delete repeater_; }
+
+// Returns the standard listener responsible for the default console
+// output. Can be removed from the listeners list to shut down default
+// console output. Note that removing this object from the listener list
+// with Release transfers its ownership to the user.
+void TestEventListeners::Append(TestEventListener* listener) {
+ repeater_->Append(listener);
+}
+
+// Removes the given event listener from the list and returns it. It then
+// becomes the caller's responsibility to delete the listener. Returns
+// NULL if the listener is not found in the list.
+TestEventListener* TestEventListeners::Release(TestEventListener* listener) {
+ if (listener == default_result_printer_)
+ default_result_printer_ = NULL;
+ else if (listener == default_xml_generator_)
+ default_xml_generator_ = NULL;
+ return repeater_->Release(listener);
+}
+
+// Returns repeater that broadcasts the TestEventListener events to all
+// subscribers.
+TestEventListener* TestEventListeners::repeater() { return repeater_; }
+
+// Sets the default_result_printer attribute to the provided listener.
+// The listener is also added to the listener list and previous
+// default_result_printer is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {
+ if (default_result_printer_ != listener) {
+ // It is an error to pass this method a listener that is already in the
+ // list.
+ delete Release(default_result_printer_);
+ default_result_printer_ = listener;
+ if (listener != NULL)
+ Append(listener);
+ }
+}
+
+// Sets the default_xml_generator attribute to the provided listener. The
+// listener is also added to the listener list and previous
+// default_xml_generator is removed from it and deleted. The listener can
+// also be NULL in which case it will not be added to the list. Does
+// nothing if the previous and the current listener objects are the same.
+void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) {
+ if (default_xml_generator_ != listener) {
+ // It is an error to pass this method a listener that is already in the
+ // list.
+ delete Release(default_xml_generator_);
+ default_xml_generator_ = listener;
+ if (listener != NULL)
+ Append(listener);
+ }
+}
+
+// Controls whether events will be forwarded by the repeater to the
+// listeners in the list.
+bool TestEventListeners::EventForwardingEnabled() const {
+ return repeater_->forwarding_enabled();
+}
+
+void TestEventListeners::SuppressEventForwarding() {
+ repeater_->set_forwarding_enabled(false);
+}
+
+// class UnitTest
+
+// Gets the singleton UnitTest object. The first time this method is
+// called, a UnitTest object is constructed and returned. Consecutive
+// calls will return the same object.
+//
+// We don't protect this under mutex_ as a user is not supposed to
+// call this before main() starts, from which point on the return
+// value will never change.
+UnitTest * UnitTest::GetInstance() {
+ // When compiled with MSVC 7.1 in optimized mode, destroying the
+ // UnitTest object upon exiting the program messes up the exit code,
+ // causing successful tests to appear failed. We have to use a
+ // different implementation in this case to bypass the compiler bug.
+ // This implementation makes the compiler happy, at the cost of
+ // leaking the UnitTest object.
+
+ // CodeGear C++Builder insists on a public destructor for the
+ // default implementation. Use this implementation to keep good OO
+ // design with private destructor.
+
+#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+ static UnitTest* const instance = new UnitTest;
+ return instance;
+#else
+ static UnitTest instance;
+ return &instance;
+#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
+}
+
+// Gets the number of successful test cases.
+int UnitTest::successful_test_case_count() const {
+ return impl()->successful_test_case_count();
+}
+
+// Gets the number of failed test cases.
+int UnitTest::failed_test_case_count() const {
+ return impl()->failed_test_case_count();
+}
+
+// Gets the number of all test cases.
+int UnitTest::total_test_case_count() const {
+ return impl()->total_test_case_count();
+}
+
+// Gets the number of all test cases that contain at least one test
+// that should run.
+int UnitTest::test_case_to_run_count() const {
+ return impl()->test_case_to_run_count();
+}
+
+// Gets the number of successful tests.
+int UnitTest::successful_test_count() const {
+ return impl()->successful_test_count();
+}
+
+// Gets the number of failed tests.
+int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
+
+// Gets the number of disabled tests.
+int UnitTest::disabled_test_count() const {
+ return impl()->disabled_test_count();
+}
+
+// Gets the number of all tests.
+int UnitTest::total_test_count() const { return impl()->total_test_count(); }
+
+// Gets the number of tests that should run.
+int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
+
+// Gets the elapsed time, in milliseconds.
+internal::TimeInMillis UnitTest::elapsed_time() const {
+ return impl()->elapsed_time();
+}
+
+// Returns true iff the unit test passed (i.e. all test cases passed).
+bool UnitTest::Passed() const { return impl()->Passed(); }
+
+// Returns true iff the unit test failed (i.e. some test case failed
+// or something outside of all tests failed).
+bool UnitTest::Failed() const { return impl()->Failed(); }
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+const TestCase* UnitTest::GetTestCase(int i) const {
+ return impl()->GetTestCase(i);
+}
+
+// Gets the i-th test case among all the test cases. i can range from 0 to
+// total_test_case_count() - 1. If i is not in that range, returns NULL.
+TestCase* UnitTest::GetMutableTestCase(int i) {
+ return impl()->GetMutableTestCase(i);
+}
+
+// Returns the list of event listeners that can be used to track events
+// inside Google Test.
+TestEventListeners& UnitTest::listeners() {
+ return *impl()->listeners();
+}
+
+// Registers and returns a global test environment. When a test
+// program is run, all global test environments will be set-up in the
+// order they were registered. After all tests in the program have
+// finished, all global test environments will be torn-down in the
+// *reverse* order they were registered.
+//
+// The UnitTest object takes ownership of the given environment.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+Environment* UnitTest::AddEnvironment(Environment* env) {
+ if (env == NULL) {
+ return NULL;
+ }
+
+ impl_->environments().push_back(env);
+ return env;
+}
+
+#if GTEST_HAS_EXCEPTIONS
+// A failed Google Test assertion will throw an exception of this type
+// when exceptions are enabled. We derive it from std::runtime_error,
+// which is for errors presumably detectable only at run time. Since
+// std::runtime_error inherits from std::exception, many testing
+// frameworks know how to extract and print the message inside it.
+class GoogleTestFailureException : public ::std::runtime_error {
+ public:
+ explicit GoogleTestFailureException(const TestPartResult& failure)
+ : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+};
+#endif
+
+// Adds a TestPartResult to the current TestResult object. All Google Test
+// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
+// this to report their results. The user code should use the
+// assertion macros instead of calling this directly.
+// L < mutex_
+void UnitTest::AddTestPartResult(TestPartResult::Type result_type,
+ const char* file_name,
+ int line_number,
+ const internal::String& message,
+ const internal::String& os_stack_trace) {
+ Message msg;
+ msg << message;
+
+ internal::MutexLock lock(&mutex_);
+ if (impl_->gtest_trace_stack().size() > 0) {
+ msg << "\n" << GTEST_NAME_ << " trace:";
+
+ for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
+ i > 0; --i) {
+ const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
+ msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
+ << " " << trace.message;
+ }
+ }
+
+ if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
+ msg << internal::kStackTraceMarker << os_stack_trace;
+ }
+
+ const TestPartResult result =
+ TestPartResult(result_type, file_name, line_number,
+ msg.GetString().c_str());
+ impl_->GetTestPartResultReporterForCurrentThread()->
+ ReportTestPartResult(result);
+
+ if (result_type != TestPartResult::kSuccess) {
+ // gtest_break_on_failure takes precedence over
+ // gtest_throw_on_failure. This allows a user to set the latter
+ // in the code (perhaps in order to use Google Test assertions
+ // with another testing framework) and specify the former on the
+ // command line for debugging.
+ if (GTEST_FLAG(break_on_failure)) {
+#if GTEST_OS_WINDOWS
+ // Using DebugBreak on Windows allows gtest to still break into a debugger
+ // when a failure happens and both the --gtest_break_on_failure and
+ // the --gtest_catch_exceptions flags are specified.
+ DebugBreak();
+#else
+ *static_cast<volatile int*>(NULL) = 1;
+#endif // GTEST_OS_WINDOWS
+ } else if (GTEST_FLAG(throw_on_failure)) {
+#if GTEST_HAS_EXCEPTIONS
+ throw GoogleTestFailureException(result);
+#else
+ // We cannot call abort() as it generates a pop-up in debug mode
+ // that cannot be suppressed in VC 7.1 or below.
+ exit(1);
+#endif
+ }
+ }
+}
+
+// Creates and adds a property to the current TestResult. If a property matching
+// the supplied value already exists, updates its value instead.
+void UnitTest::RecordPropertyForCurrentTest(const char* key,
+ const char* value) {
+ const TestProperty test_property(key, value);
+ impl_->current_test_result()->RecordProperty(test_property);
+}
+
+// Runs all tests in this UnitTest object and prints the result.
+// Returns 0 if successful, or 1 otherwise.
+//
+// We don't protect this under mutex_, as we only support calling it
+// from the main thread.
+int UnitTest::Run() {
+#if GTEST_HAS_SEH
+ // Catch SEH-style exceptions.
+
+ const bool in_death_test_child_process =
+ internal::GTEST_FLAG(internal_run_death_test).length() > 0;
+
+ // Either the user wants Google Test to catch exceptions thrown by the
+ // tests or this is executing in the context of death test child
+ // process. In either case the user does not want to see pop-up dialogs
+ // about crashes - they are expected..
+ if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) {
+#if !GTEST_OS_WINDOWS_MOBILE
+ // SetErrorMode doesn't exist on CE.
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
+ SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+#if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
+ // Death test children can be terminated with _abort(). On Windows,
+ // _abort() can show a dialog with a warning message. This forces the
+ // abort message to go to stderr instead.
+ _set_error_mode(_OUT_TO_STDERR);
+#endif
+
+#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
+ // In the debug version, Visual Studio pops up a separate dialog
+ // offering a choice to debug the aborted program. We need to suppress
+ // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
+ // executed. Google Test will notify the user of any unexpected
+ // failure via stderr.
+ //
+ // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
+ // Users of prior VC versions shall suffer the agony and pain of
+ // clicking through the countless debug dialogs.
+ // TODO(vladl@google.com): find a way to suppress the abort dialog() in the
+ // debug mode when compiled with VC 7.1 or lower.
+ if (!GTEST_FLAG(break_on_failure))
+ _set_abort_behavior(
+ 0x0, // Clear the following flags:
+ _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
+#endif
+ }
+
+ __try {
+ return impl_->RunAllTests();
+ } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
+ GetExceptionCode())) {
+ printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode());
+ fflush(stdout);
+ return 1;
+ }
+
+#else // We are on a compiler or platform that doesn't support SEH.
+
+ return impl_->RunAllTests();
+#endif // GTEST_HAS_SEH
+}
+
+// Returns the working directory when the first TEST() or TEST_F() was
+// executed.
+const char* UnitTest::original_working_dir() const {
+ return impl_->original_working_dir_.c_str();
+}
+
+// Returns the TestCase object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestCase* UnitTest::current_test_case() const {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_case();
+}
+
+// Returns the TestInfo object for the test that's currently running,
+// or NULL if no test is running.
+// L < mutex_
+const TestInfo* UnitTest::current_test_info() const {
+ internal::MutexLock lock(&mutex_);
+ return impl_->current_test_info();
+}
+
+// Returns the random seed used at the start of the current test run.
+int UnitTest::random_seed() const { return impl_->random_seed(); }
+
+#if GTEST_HAS_PARAM_TEST
+// Returns ParameterizedTestCaseRegistry object used to keep track of
+// value-parameterized tests and instantiate and register them.
+// L < mutex_
+internal::ParameterizedTestCaseRegistry&
+ UnitTest::parameterized_test_registry() {
+ return impl_->parameterized_test_registry();
+}
+#endif // GTEST_HAS_PARAM_TEST
+
+// Creates an empty UnitTest.
+UnitTest::UnitTest() {
+ impl_ = new internal::UnitTestImpl(this);
+}
+
+// Destructor of UnitTest.
+UnitTest::~UnitTest() {
+ delete impl_;
+}
+
+// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
+// Google Test trace stack.
+// L < mutex_
+void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().push_back(trace);
+}
+
+// Pops a trace from the per-thread Google Test trace stack.
+// L < mutex_
+void UnitTest::PopGTestTrace() {
+ internal::MutexLock lock(&mutex_);
+ impl_->gtest_trace_stack().pop_back();
+}
+
+namespace internal {
+
+UnitTestImpl::UnitTestImpl(UnitTest* parent)
+ : parent_(parent),
+#ifdef _MSC_VER
+#pragma warning(push) // Saves the current warning state.
+#pragma warning(disable:4355) // Temporarily disables warning 4355
+ // (using this in initializer).
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+#pragma warning(pop) // Restores the warning state again.
+#else
+ default_global_test_part_result_reporter_(this),
+ default_per_thread_test_part_result_reporter_(this),
+#endif // _MSC_VER
+ global_test_part_result_repoter_(
+ &default_global_test_part_result_reporter_),
+ per_thread_test_part_result_reporter_(
+ &default_per_thread_test_part_result_reporter_),
+#if GTEST_HAS_PARAM_TEST
+ parameterized_test_registry_(),
+ parameterized_tests_registered_(false),
+#endif // GTEST_HAS_PARAM_TEST
+ last_death_test_case_(-1),
+ current_test_case_(NULL),
+ current_test_info_(NULL),
+ ad_hoc_test_result_(),
+ os_stack_trace_getter_(NULL),
+ post_flag_parse_init_performed_(false),
+ random_seed_(0), // Will be overridden by the flag before first use.
+ random_(0), // Will be reseeded before first use.
+#if GTEST_HAS_DEATH_TEST
+ elapsed_time_(0),
+ internal_run_death_test_flag_(NULL),
+ death_test_factory_(new DefaultDeathTestFactory) {
+#else
+ elapsed_time_(0) {
+#endif // GTEST_HAS_DEATH_TEST
+ listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
+}
+
+UnitTestImpl::~UnitTestImpl() {
+ // Deletes every TestCase.
+ ForEach(test_cases_, internal::Delete<TestCase>);
+
+ // Deletes every Environment.
+ ForEach(environments_, internal::Delete<Environment>);
+
+ delete os_stack_trace_getter_;
+}
+
+#if GTEST_HAS_DEATH_TEST
+// Disables event forwarding if the control is currently in a death test
+// subprocess. Must not be called before InitGoogleTest.
+void UnitTestImpl::SuppressTestEventsIfInSubprocess() {
+ if (internal_run_death_test_flag_.get() != NULL)
+ listeners()->SuppressEventForwarding();
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// Initializes event listeners performing XML output as specified by
+// UnitTestOptions. Must not be called before InitGoogleTest.
+void UnitTestImpl::ConfigureXmlOutput() {
+ const String& output_format = UnitTestOptions::GetOutputFormat();
+ if (output_format == "xml") {
+ listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
+ } else if (output_format != "") {
+ printf("WARNING: unrecognized output format \"%s\" ignored.\n",
+ output_format.c_str());
+ fflush(stdout);
+ }
+}
+
+// Performs initialization dependent upon flag values obtained in
+// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
+// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
+// this function is also called from RunAllTests. Since this function can be
+// called more than once, it has to be idempotent.
+void UnitTestImpl::PostFlagParsingInit() {
+ // Ensures that this function does not execute more than once.
+ if (!post_flag_parse_init_performed_) {
+ post_flag_parse_init_performed_ = true;
+
+#if GTEST_HAS_DEATH_TEST
+ InitDeathTestSubprocessControlInfo();
+ SuppressTestEventsIfInSubprocess();
+#endif // GTEST_HAS_DEATH_TEST
+
+ // Registers parameterized tests. This makes parameterized tests
+ // available to the UnitTest reflection API without running
+ // RUN_ALL_TESTS.
+ RegisterParameterizedTests();
+
+ // Configures listeners for XML output. This makes it possible for users
+ // to shut down the default XML output before invoking RUN_ALL_TESTS.
+ ConfigureXmlOutput();
+ }
+}
+
+// A predicate that checks the name of a TestCase against a known
+// value.
+//
+// This is used for implementation of the UnitTest class only. We put
+// it in the anonymous namespace to prevent polluting the outer
+// namespace.
+//
+// TestCaseNameIs is copyable.
+class TestCaseNameIs {
+ public:
+ // Constructor.
+ explicit TestCaseNameIs(const String& name)
+ : name_(name) {}
+
+ // Returns true iff the name of test_case matches name_.
+ bool operator()(const TestCase* test_case) const {
+ return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
+ }
+
+ private:
+ String name_;
+};
+
+// Finds and returns a TestCase with the given name. If one doesn't
+// exist, creates one and returns it. It's the CALLER'S
+// RESPONSIBILITY to ensure that this function is only called WHEN THE
+// TESTS ARE NOT SHUFFLED.
+//
+// Arguments:
+//
+// test_case_name: name of the test case
+// set_up_tc: pointer to the function that sets up the test case
+// tear_down_tc: pointer to the function that tears down the test case
+TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
+ const char* comment,
+ Test::SetUpTestCaseFunc set_up_tc,
+ Test::TearDownTestCaseFunc tear_down_tc) {
+ // Can we find a TestCase with the given name?
+ const std::vector<TestCase*>::const_iterator test_case =
+ std::find_if(test_cases_.begin(), test_cases_.end(),
+ TestCaseNameIs(test_case_name));
+
+ if (test_case != test_cases_.end())
+ return *test_case;
+
+ // No. Let's create one.
+ TestCase* const new_test_case =
+ new TestCase(test_case_name, comment, set_up_tc, tear_down_tc);
+
+ // Is this a death test case?
+ if (internal::UnitTestOptions::MatchesFilter(String(test_case_name),
+ kDeathTestCaseFilter)) {
+ // Yes. Inserts the test case after the last death test case
+ // defined so far. This only works when the test cases haven't
+ // been shuffled. Otherwise we may end up running a death test
+ // after a non-death test.
+ ++last_death_test_case_;
+ test_cases_.insert(test_cases_.begin() + last_death_test_case_,
+ new_test_case);
+ } else {
+ // No. Appends to the end of the list.
+ test_cases_.push_back(new_test_case);
+ }
+
+ test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
+ return new_test_case;
+}
+
+// Helpers for setting up / tearing down the given environment. They
+// are for use in the ForEach() function.
+static void SetUpEnvironment(Environment* env) { env->SetUp(); }
+static void TearDownEnvironment(Environment* env) { env->TearDown(); }
+
+// Runs all tests in this UnitTest object, prints the result, and
+// returns 0 if all tests are successful, or 1 otherwise. If any
+// exception is thrown during a test on Windows, this test is
+// considered to be failed, but the rest of the tests will still be
+// run. (We disable exceptions on Linux and Mac OS X, so the issue
+// doesn't apply there.)
+// When parameterized tests are enabled, it expands and registers
+// parameterized tests first in RegisterParameterizedTests().
+// All other functions called from RunAllTests() may safely assume that
+// parameterized tests are ready to be counted and run.
+int UnitTestImpl::RunAllTests() {
+ // Makes sure InitGoogleTest() was called.
+ if (!GTestIsInitialized()) {
+ printf("%s",
+ "\nThis test program did NOT call ::testing::InitGoogleTest "
+ "before calling RUN_ALL_TESTS(). Please fix it.\n");
+ return 1;
+ }
+
+ // Do not run any test if the --help flag was specified.
+ if (g_help_flag)
+ return 0;
+
+ // Repeats the call to the post-flag parsing initialization in case the
+ // user didn't call InitGoogleTest.
+ PostFlagParsingInit();
+
+ // Even if sharding is not on, test runners may want to use the
+ // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
+ // protocol.
+ internal::WriteToShardStatusFileIfNeeded();
+
+ // True iff we are in a subprocess for running a thread-safe-style
+ // death test.
+ bool in_subprocess_for_death_test = false;
+
+#if GTEST_HAS_DEATH_TEST
+ in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+#endif // GTEST_HAS_DEATH_TEST
+
+ const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
+ in_subprocess_for_death_test);
+
+ // Compares the full test names with the filter to decide which
+ // tests to run.
+ const bool has_tests_to_run = FilterTests(should_shard
+ ? HONOR_SHARDING_PROTOCOL
+ : IGNORE_SHARDING_PROTOCOL) > 0;
+
+ // Lists the tests and exits if the --gtest_list_tests flag was specified.
+ if (GTEST_FLAG(list_tests)) {
+ // This must be called *after* FilterTests() has been called.
+ ListTestsMatchingFilter();
+ return 0;
+ }
+
+ random_seed_ = GTEST_FLAG(shuffle) ?
+ GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
+
+ // True iff at least one test has failed.
+ bool failed = false;
+
+ TestEventListener* repeater = listeners()->repeater();
+
+ repeater->OnTestProgramStart(*parent_);
+
+ // How many times to repeat the tests? We don't want to repeat them
+ // when we are inside the subprocess of a death test.
+ const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
+ // Repeats forever if the repeat count is negative.
+ const bool forever = repeat < 0;
+ for (int i = 0; forever || i != repeat; i++) {
+ ClearResult();
+
+ const TimeInMillis start = GetTimeInMillis();
+
+ // Shuffles test cases and tests if requested.
+ if (has_tests_to_run && GTEST_FLAG(shuffle)) {
+ random()->Reseed(random_seed_);
+ // This should be done before calling OnTestIterationStart(),
+ // such that a test event listener can see the actual test order
+ // in the event.
+ ShuffleTests();
+ }
+
+ // Tells the unit test event listeners that the tests are about to start.
+ repeater->OnTestIterationStart(*parent_, i);
+
+ // Runs each test case if there is at least one test to run.
+ if (has_tests_to_run) {
+ // Sets up all environments beforehand.
+ repeater->OnEnvironmentsSetUpStart(*parent_);
+ ForEach(environments_, SetUpEnvironment);
+ repeater->OnEnvironmentsSetUpEnd(*parent_);
+
+ // Runs the tests only if there was no fatal failure during global
+ // set-up.
+ if (!Test::HasFatalFailure()) {
+ for (int test_index = 0; test_index < total_test_case_count();
+ test_index++) {
+ GetMutableTestCase(test_index)->Run();
+ }
+ }
+
+ // Tears down all environments in reverse order afterwards.
+ repeater->OnEnvironmentsTearDownStart(*parent_);
+ std::for_each(environments_.rbegin(), environments_.rend(),
+ TearDownEnvironment);
+ repeater->OnEnvironmentsTearDownEnd(*parent_);
+ }
+
+ elapsed_time_ = GetTimeInMillis() - start;
+
+ // Tells the unit test event listener that the tests have just finished.
+ repeater->OnTestIterationEnd(*parent_, i);
+
+ // Gets the result and clears it.
+ if (!Passed()) {
+ failed = true;
+ }
+
+ // Restores the original test order after the iteration. This
+ // allows the user to quickly repro a failure that happens in the
+ // N-th iteration without repeating the first (N - 1) iterations.
+ // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
+ // case the user somehow changes the value of the flag somewhere
+ // (it's always safe to unshuffle the tests).
+ UnshuffleTests();
+
+ if (GTEST_FLAG(shuffle)) {
+ // Picks a new random seed for each iteration.
+ random_seed_ = GetNextRandomSeed(random_seed_);
+ }
+ }
+
+ repeater->OnTestProgramEnd(*parent_);
+
+ // Returns 0 if all tests passed, or 1 other wise.
+ return failed ? 1 : 0;
+}
+
+// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
+// if the variable is present. If a file already exists at this location, this
+// function will write over it. If the variable is present, but the file cannot
+// be created, prints an error and exits.
+void WriteToShardStatusFileIfNeeded() {
+ const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
+ if (test_shard_file != NULL) {
+ FILE* const file = posix::FOpen(test_shard_file, "w");
+ if (file == NULL) {
+ ColoredPrintf(COLOR_RED,
+ "Could not write to the test shard status file \"%s\" "
+ "specified by the %s environment variable.\n",
+ test_shard_file, kTestShardStatusFile);
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ }
+ fclose(file);
+ }
+}
+
+// Checks whether sharding is enabled by examining the relevant
+// environment variable values. If the variables are present,
+// but inconsistent (i.e., shard_index >= total_shards), prints
+// an error and exits. If in_subprocess_for_death_test, sharding is
+// disabled because it must only be applied to the original test
+// process. Otherwise, we could filter out death tests we intended to execute.
+bool ShouldShard(const char* total_shards_env,
+ const char* shard_index_env,
+ bool in_subprocess_for_death_test) {
+ if (in_subprocess_for_death_test) {
+ return false;
+ }
+
+ const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
+ const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);
+
+ if (total_shards == -1 && shard_index == -1) {
+ return false;
+ } else if (total_shards == -1 && shard_index != -1) {
+ const Message msg = Message()
+ << "Invalid environment variables: you have "
+ << kTestShardIndex << " = " << shard_index
+ << ", but have left " << kTestTotalShards << " unset.\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ } else if (total_shards != -1 && shard_index == -1) {
+ const Message msg = Message()
+ << "Invalid environment variables: you have "
+ << kTestTotalShards << " = " << total_shards
+ << ", but have left " << kTestShardIndex << " unset.\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ } else if (shard_index < 0 || shard_index >= total_shards) {
+ const Message msg = Message()
+ << "Invalid environment variables: we require 0 <= "
+ << kTestShardIndex << " < " << kTestTotalShards
+ << ", but you have " << kTestShardIndex << "=" << shard_index
+ << ", " << kTestTotalShards << "=" << total_shards << ".\n";
+ ColoredPrintf(COLOR_RED, msg.GetString().c_str());
+ fflush(stdout);
+ exit(EXIT_FAILURE);
+ }
+
+ return total_shards > 1;
+}
+
+// Parses the environment variable var as an Int32. If it is unset,
+// returns default_val. If it is not an Int32, prints an error
+// and aborts.
+Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) {
+ const char* str_val = posix::GetEnv(var);
+ if (str_val == NULL) {
+ return default_val;
+ }
+
+ Int32 result;
+ if (!ParseInt32(Message() << "The value of environment variable " << var,
+ str_val, &result)) {
+ exit(EXIT_FAILURE);
+ }
+ return result;
+}
+
+// Given the total number of shards, the shard index, and the test id,
+// returns true iff the test should be run on this shard. The test id is
+// some arbitrary but unique non-negative integer assigned to each test
+// method. Assumes that 0 <= shard_index < total_shards.
+bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
+ return (test_id % total_shards) == shard_index;
+}
+
+// Compares the name of each test with the user-specified filter to
+// decide whether the test should be run, then records the result in
+// each TestCase and TestInfo object.
+// If shard_tests == true, further filters tests based on sharding
+// variables in the environment - see
+// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
+// Returns the number of tests that should run.
+int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
+ const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
+ Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
+ const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
+ Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
+
+ // num_runnable_tests are the number of tests that will
+ // run across all shards (i.e., match filter and are not disabled).
+ // num_selected_tests are the number of tests to be run on
+ // this shard.
+ int num_runnable_tests = 0;
+ int num_selected_tests = 0;
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ TestCase* const test_case = test_cases_[i];
+ const String &test_case_name = test_case->name();
+ test_case->set_should_run(false);
+
+ for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+ TestInfo* const test_info = test_case->test_info_list()[j];
+ const String test_name(test_info->name());
+ // A test is disabled if test case name or test name matches
+ // kDisableTestFilter.
+ const bool is_disabled =
+ internal::UnitTestOptions::MatchesFilter(test_case_name,
+ kDisableTestFilter) ||
+ internal::UnitTestOptions::MatchesFilter(test_name,
+ kDisableTestFilter);
+ test_info->impl()->set_is_disabled(is_disabled);
+
+ const bool matches_filter =
+ internal::UnitTestOptions::FilterMatchesTest(test_case_name,
+ test_name);
+ test_info->impl()->set_matches_filter(matches_filter);
+
+ const bool is_runnable =
+ (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
+ matches_filter;
+
+ const bool is_selected = is_runnable &&
+ (shard_tests == IGNORE_SHARDING_PROTOCOL ||
+ ShouldRunTestOnShard(total_shards, shard_index,
+ num_runnable_tests));
+
+ num_runnable_tests += is_runnable;
+ num_selected_tests += is_selected;
+
+ test_info->impl()->set_should_run(is_selected);
+ test_case->set_should_run(test_case->should_run() || is_selected);
+ }
+ }
+ return num_selected_tests;
+}
+
+// Prints the names of the tests matching the user-specified filter flag.
+void UnitTestImpl::ListTestsMatchingFilter() {
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ const TestCase* const test_case = test_cases_[i];
+ bool printed_test_case_name = false;
+
+ for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
+ const TestInfo* const test_info =
+ test_case->test_info_list()[j];
+ if (test_info->matches_filter()) {
+ if (!printed_test_case_name) {
+ printed_test_case_name = true;
+ printf("%s.\n", test_case->name());
+ }
+ printf(" %s\n", test_info->name());
+ }
+ }
+ }
+ fflush(stdout);
+}
+
+// Sets the OS stack trace getter.
+//
+// Does nothing if the input and the current OS stack trace getter are
+// the same; otherwise, deletes the old getter and makes the input the
+// current getter.
+void UnitTestImpl::set_os_stack_trace_getter(
+ OsStackTraceGetterInterface* getter) {
+ if (os_stack_trace_getter_ != getter) {
+ delete os_stack_trace_getter_;
+ os_stack_trace_getter_ = getter;
+ }
+}
+
+// Returns the current OS stack trace getter if it is not NULL;
+// otherwise, creates an OsStackTraceGetter, makes it the current
+// getter, and returns it.
+OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
+ if (os_stack_trace_getter_ == NULL) {
+ os_stack_trace_getter_ = new OsStackTraceGetter;
+ }
+
+ return os_stack_trace_getter_;
+}
+
+// Returns the TestResult for the test that's currently running, or
+// the TestResult for the ad hoc test if no test is running.
+TestResult* UnitTestImpl::current_test_result() {
+ return current_test_info_ ?
+ current_test_info_->impl()->result() : &ad_hoc_test_result_;
+}
+
+// Shuffles all test cases, and the tests within each test case,
+// making sure that death tests are still run first.
+void UnitTestImpl::ShuffleTests() {
+ // Shuffles the death test cases.
+ ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_);
+
+ // Shuffles the non-death test cases.
+ ShuffleRange(random(), last_death_test_case_ + 1,
+ static_cast<int>(test_cases_.size()), &test_case_indices_);
+
+ // Shuffles the tests inside each test case.
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ test_cases_[i]->ShuffleTests(random());
+ }
+}
+
+// Restores the test cases and tests to their order before the first shuffle.
+void UnitTestImpl::UnshuffleTests() {
+ for (size_t i = 0; i < test_cases_.size(); i++) {
+ // Unshuffles the tests in each test case.
+ test_cases_[i]->UnshuffleTests();
+ // Resets the index of each test case.
+ test_case_indices_[i] = static_cast<int>(i);
+ }
+}
+
+// TestInfoImpl constructor. The new instance assumes ownership of the test
+// factory object.
+TestInfoImpl::TestInfoImpl(TestInfo* parent,
+ const char* a_test_case_name,
+ const char* a_name,
+ const char* a_test_case_comment,
+ const char* a_comment,
+ TypeId a_fixture_class_id,
+ internal::TestFactoryBase* factory) :
+ parent_(parent),
+ test_case_name_(String(a_test_case_name)),
+ name_(String(a_name)),
+ test_case_comment_(String(a_test_case_comment)),
+ comment_(String(a_comment)),
+ fixture_class_id_(a_fixture_class_id),
+ should_run_(false),
+ is_disabled_(false),
+ matches_filter_(false),
+ factory_(factory) {
+}
+
+// TestInfoImpl destructor.
+TestInfoImpl::~TestInfoImpl() {
+ delete factory_;
+}
+
+// Returns the current OS stack trace as a String.
+//
+// The maximum number of stack frames to be included is specified by
+// the gtest_stack_trace_depth flag. The skip_count parameter
+// specifies the number of top frames to be skipped, which doesn't
+// count against the number of frames to be included.
+//
+// For example, if Foo() calls Bar(), which in turn calls
+// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
+// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
+String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/,
+ int skip_count) {
+ // We pass skip_count + 1 to skip this wrapper function in addition
+ // to what the user really wants to skip.
+ return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
+}
+
+// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable
+// code warnings.
+namespace {
+class ClassUniqueToAlwaysTrue {};
+}
+
+bool IsTrue(bool condition) { return condition; }
+
+bool AlwaysTrue() {
+#if GTEST_HAS_EXCEPTIONS
+ // This condition is always false so AlwaysTrue() never actually throws,
+ // but it makes the compiler think that it may throw.
+ if (IsTrue(false))
+ throw ClassUniqueToAlwaysTrue();
+#endif // GTEST_HAS_EXCEPTIONS
+ return true;
+}
+
+// If *pstr starts with the given prefix, modifies *pstr to be right
+// past the prefix and returns true; otherwise leaves *pstr unchanged
+// and returns false. None of pstr, *pstr, and prefix can be NULL.
+bool SkipPrefix(const char* prefix, const char** pstr) {
+ const size_t prefix_len = strlen(prefix);
+ if (strncmp(*pstr, prefix, prefix_len) == 0) {
+ *pstr += prefix_len;
+ return true;
+ }
+ return false;
+}
+
+// Parses a string as a command line flag. The string should have
+// the format "--flag=value". When def_optional is true, the "=value"
+// part can be omitted.
+//
+// Returns the value of the flag, or NULL if the parsing failed.
+const char* ParseFlagValue(const char* str,
+ const char* flag,
+ bool def_optional) {
+ // str and flag must not be NULL.
+ if (str == NULL || flag == NULL) return NULL;
+
+ // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
+ const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag);
+ const size_t flag_len = flag_str.length();
+ if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
+
+ // Skips the flag name.
+ const char* flag_end = str + flag_len;
+
+ // When def_optional is true, it's OK to not have a "=value" part.
+ if (def_optional && (flag_end[0] == '\0')) {
+ return flag_end;
+ }
+
+ // If def_optional is true and there are more characters after the
+ // flag name, or if def_optional is false, there must be a '=' after
+ // the flag name.
+ if (flag_end[0] != '=') return NULL;
+
+ // Returns the string after "=".
+ return flag_end + 1;
+}
+
+// Parses a string for a bool flag, in the form of either
+// "--flag=value" or "--flag".
+//
+// In the former case, the value is taken as true as long as it does
+// not start with '0', 'f', or 'F'.
+//
+// In the latter case, the value is taken as true.
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, true);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Converts the string value to a bool.
+ *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
+ return true;
+}
+
+// Parses a string for an Int32 flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ return ParseInt32(Message() << "The value of flag --" << flag,
+ value_str, value);
+}
+
+// Parses a string for a string flag, in the form of
+// "--flag=value".
+//
+// On success, stores the value of the flag in *value, and returns
+// true. On failure, returns false without changing *value.
+bool ParseStringFlag(const char* str, const char* flag, String* value) {
+ // Gets the value of the flag as a string.
+ const char* const value_str = ParseFlagValue(str, flag, false);
+
+ // Aborts if the parsing failed.
+ if (value_str == NULL) return false;
+
+ // Sets *value to the value of the flag.
+ *value = value_str;
+ return true;
+}
+
+// Determines whether a string has a prefix that Google Test uses for its
+// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_.
+// If Google Test detects that a command line flag has its prefix but is not
+// recognized, it will print its help message. Flags starting with
+// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test
+// internal flags and do not trigger the help message.
+static bool HasGoogleTestFlagPrefix(const char* str) {
+ return (SkipPrefix("--", &str) ||
+ SkipPrefix("-", &str) ||
+ SkipPrefix("/", &str)) &&
+ !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) &&
+ (SkipPrefix(GTEST_FLAG_PREFIX_, &str) ||
+ SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str));
+}
+
+// Prints a string containing code-encoded text. The following escape
+// sequences can be used in the string to control the text color:
+//
+// @@ prints a single '@' character.
+// @R changes the color to red.
+// @G changes the color to green.
+// @Y changes the color to yellow.
+// @D changes to the default terminal text color.
+//
+// TODO(wan@google.com): Write tests for this once we add stdout
+// capturing to Google Test.
+static void PrintColorEncoded(const char* str) {
+ GTestColor color = COLOR_DEFAULT; // The current color.
+
+ // Conceptually, we split the string into segments divided by escape
+ // sequences. Then we print one segment at a time. At the end of
+ // each iteration, the str pointer advances to the beginning of the
+ // next segment.
+ for (;;) {
+ const char* p = strchr(str, '@');
+ if (p == NULL) {
+ ColoredPrintf(color, "%s", str);
+ return;
+ }
+
+ ColoredPrintf(color, "%s", String(str, p - str).c_str());
+
+ const char ch = p[1];
+ str = p + 2;
+ if (ch == '@') {
+ ColoredPrintf(color, "@");
+ } else if (ch == 'D') {
+ color = COLOR_DEFAULT;
+ } else if (ch == 'R') {
+ color = COLOR_RED;
+ } else if (ch == 'G') {
+ color = COLOR_GREEN;
+ } else if (ch == 'Y') {
+ color = COLOR_YELLOW;
+ } else {
+ --str;
+ }
+ }
+}
+
+static const char kColorEncodedHelpMessage[] =
+"This program contains tests written using " GTEST_NAME_ ". You can use the\n"
+"following command line flags to control its behavior:\n"
+"\n"
+"Test Selection:\n"
+" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n"
+" List the names of all tests instead of running them. The name of\n"
+" TEST(Foo, Bar) is \"Foo.Bar\".\n"
+" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
+ "[@G-@YNEGATIVE_PATTERNS]@D\n"
+" Run only the tests whose name matches one of the positive patterns but\n"
+" none of the negative patterns. '?' matches any single character; '*'\n"
+" matches any substring; ':' separates two patterns.\n"
+" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n"
+" Run all disabled tests too.\n"
+"\n"
+"Test Execution:\n"
+" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
+" Run the tests repeatedly; use a negative count to repeat forever.\n"
+" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n"
+" Randomize tests' orders on every iteration.\n"
+" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n"
+" Random number seed to use for shuffling test orders (between 1 and\n"
+" 99999, or 0 to use a seed based on the current time).\n"
+"\n"
+"Test Output:\n"
+" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
+" Enable/disable colored output. The default is @Gauto@D.\n"
+" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"
+" Don't print the elapsed time of each test.\n"
+" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G"
+ GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
+" Generate an XML report in the given directory or with the given file\n"
+" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n"
+"\n"
+"Assertion Behavior:\n"
+#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
+" Set the default death test style.\n"
+#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
+" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
+" Turn assertion failures into debugger break-points.\n"
+" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
+" Turn assertion failures into C++ exceptions.\n"
+#if GTEST_OS_WINDOWS
+" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n"
+" Suppress pop-ups caused by exceptions.\n"
+#endif // GTEST_OS_WINDOWS
+"\n"
+"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set "
+ "the corresponding\n"
+"environment variable of a flag (all letters in upper-case). For example, to\n"
+"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
+ "color=no@D or set\n"
+"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n"
+"\n"
+"For more information, please read the " GTEST_NAME_ " documentation at\n"
+"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
+"(not one in your own code or tests), please report it to\n"
+"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test. The type parameter CharType can be
+// instantiated to either char or wchar_t.
+template <typename CharType>
+void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
+ for (int i = 1; i < *argc; i++) {
+ const String arg_string = StreamableToString(argv[i]);
+ const char* const arg = arg_string.c_str();
+
+ using internal::ParseBoolFlag;
+ using internal::ParseInt32Flag;
+ using internal::ParseStringFlag;
+
+ // Do we see a Google Test flag?
+ if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+ &GTEST_FLAG(also_run_disabled_tests)) ||
+ ParseBoolFlag(arg, kBreakOnFailureFlag,
+ &GTEST_FLAG(break_on_failure)) ||
+ ParseBoolFlag(arg, kCatchExceptionsFlag,
+ &GTEST_FLAG(catch_exceptions)) ||
+ ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+ ParseStringFlag(arg, kDeathTestStyleFlag,
+ &GTEST_FLAG(death_test_style)) ||
+ ParseBoolFlag(arg, kDeathTestUseFork,
+ &GTEST_FLAG(death_test_use_fork)) ||
+ ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+ ParseStringFlag(arg, kInternalRunDeathTestFlag,
+ &GTEST_FLAG(internal_run_death_test)) ||
+ ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+ ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+ ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+ ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
+ ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
+ ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
+ ParseInt32Flag(arg, kStackTraceDepthFlag,
+ &GTEST_FLAG(stack_trace_depth)) ||
+ ParseBoolFlag(arg, kThrowOnFailureFlag, &GTEST_FLAG(throw_on_failure))
+ ) {
+ // Yes. Shift the remainder of the argv list left by one. Note
+ // that argv has (*argc + 1) elements, the last one always being
+ // NULL. The following loop moves the trailing NULL element as
+ // well.
+ for (int j = i; j != *argc; j++) {
+ argv[j] = argv[j + 1];
+ }
+
+ // Decrements the argument count.
+ (*argc)--;
+
+ // We also need to decrement the iterator as we just removed
+ // an element.
+ i--;
+ } else if (arg_string == "--help" || arg_string == "-h" ||
+ arg_string == "-?" || arg_string == "/?" ||
+ HasGoogleTestFlagPrefix(arg)) {
+ // Both help flag and unrecognized Google Test flags (excluding
+ // internal ones) trigger help display.
+ g_help_flag = true;
+ }
+ }
+
+ if (g_help_flag) {
+ // We print the help here instead of in RUN_ALL_TESTS(), as the
+ // latter may not be called at all if the user is using Google
+ // Test with another testing framework.
+ PrintColorEncoded(kColorEncodedHelpMessage);
+ }
+}
+
+// Parses the command line for Google Test flags, without initializing
+// other parts of Google Test.
+void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
+ ParseGoogleTestFlagsOnlyImpl(argc, argv);
+}
+
+// The internal implementation of InitGoogleTest().
+//
+// The type parameter CharType can be instantiated to either char or
+// wchar_t.
+template <typename CharType>
+void InitGoogleTestImpl(int* argc, CharType** argv) {
+ g_init_gtest_count++;
+
+ // We don't want to run the initialization code twice.
+ if (g_init_gtest_count != 1) return;
+
+ if (*argc <= 0) return;
+
+ internal::g_executable_path = internal::StreamableToString(argv[0]);
+
+#if GTEST_HAS_DEATH_TEST
+ g_argvs.clear();
+ for (int i = 0; i != *argc; i++) {
+ g_argvs.push_back(StreamableToString(argv[i]));
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ ParseGoogleTestFlagsOnly(argc, argv);
+ GetUnitTestImpl()->PostFlagParsingInit();
+}
+
+} // namespace internal
+
+// Initializes Google Test. This must be called before calling
+// RUN_ALL_TESTS(). In particular, it parses a command line for the
+// flags that Google Test recognizes. Whenever a Google Test flag is
+// seen, it is removed from argv, and *argc is decremented.
+//
+// No value is returned. Instead, the Google Test flag variables are
+// updated.
+//
+// Calling the function for the second time has no user-visible effect.
+void InitGoogleTest(int* argc, char** argv) {
+ internal::InitGoogleTestImpl(argc, argv);
+}
+
+// This overloaded version can be used in Windows programs compiled in
+// UNICODE mode.
+void InitGoogleTest(int* argc, wchar_t** argv) {
+ internal::InitGoogleTestImpl(argc, argv);
+}
+
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/src/gtest_main.cc b/Source/ThirdParty/gtest/src/gtest_main.cc
new file mode 100644
index 000000000..d20c02fdf
--- /dev/null
+++ b/Source/ThirdParty/gtest/src/gtest_main.cc
@@ -0,0 +1,39 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ std::cout << "Running main() from gtest_main.cc\n";
+
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest-death-test_test.cc b/Source/ThirdParty/gtest/test/gtest-death-test_test.cc
new file mode 100644
index 000000000..ed5b53b71
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-death-test_test.cc
@@ -0,0 +1,1230 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Tests for death tests.
+
+#include <gtest/gtest-death-test.h>
+#include <gtest/gtest.h>
+#include <gtest/internal/gtest-filepath.h>
+
+using testing::internal::AlwaysFalse;
+using testing::internal::AlwaysTrue;
+
+#if GTEST_HAS_DEATH_TEST
+
+#if GTEST_OS_WINDOWS
+#include <direct.h> // For chdir().
+#else
+#include <unistd.h>
+#include <sys/wait.h> // For waitpid.
+#include <limits> // For std::numeric_limits.
+#endif // GTEST_OS_WINDOWS
+
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+
+#include <gtest/gtest-spi.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace posix = ::testing::internal::posix;
+
+using testing::Message;
+using testing::internal::DeathTest;
+using testing::internal::DeathTestFactory;
+using testing::internal::FilePath;
+using testing::internal::GetLastErrnoDescription;
+using testing::internal::GetUnitTestImpl;
+using testing::internal::ParseNaturalNumber;
+using testing::internal::String;
+
+namespace testing {
+namespace internal {
+
+// A helper class whose objects replace the death test factory for a
+// single UnitTest object during their lifetimes.
+class ReplaceDeathTestFactory {
+ public:
+ explicit ReplaceDeathTestFactory(DeathTestFactory* new_factory)
+ : unit_test_impl_(GetUnitTestImpl()) {
+ old_factory_ = unit_test_impl_->death_test_factory_.release();
+ unit_test_impl_->death_test_factory_.reset(new_factory);
+ }
+
+ ~ReplaceDeathTestFactory() {
+ unit_test_impl_->death_test_factory_.release();
+ unit_test_impl_->death_test_factory_.reset(old_factory_);
+ }
+ private:
+ // Prevents copying ReplaceDeathTestFactory objects.
+ ReplaceDeathTestFactory(const ReplaceDeathTestFactory&);
+ void operator=(const ReplaceDeathTestFactory&);
+
+ UnitTestImpl* unit_test_impl_;
+ DeathTestFactory* old_factory_;
+};
+
+} // namespace internal
+} // namespace testing
+
+void DieInside(const char* function) {
+ fprintf(stderr, "death inside %s().", function);
+ fflush(stderr);
+ // We call _exit() instead of exit(), as the former is a direct
+ // system call and thus safer in the presence of threads. exit()
+ // will invoke user-defined exit-hooks, which may do dangerous
+ // things that conflict with death tests.
+ //
+ // Some compilers can recognize that _exit() never returns and issue the
+ // 'unreachable code' warning for code following this function, unless
+ // fooled by a fake condition.
+ if (AlwaysTrue())
+ _exit(1);
+}
+
+// Tests that death tests work.
+
+class TestForDeathTest : public testing::Test {
+ protected:
+ TestForDeathTest() : original_dir_(FilePath::GetCurrentDir()) {}
+
+ virtual ~TestForDeathTest() {
+ posix::ChDir(original_dir_.c_str());
+ }
+
+ // A static member function that's expected to die.
+ static void StaticMemberFunction() { DieInside("StaticMemberFunction"); }
+
+ // A method of the test fixture that may die.
+ void MemberFunction() {
+ if (should_die_)
+ DieInside("MemberFunction");
+ }
+
+ // True iff MemberFunction() should die.
+ bool should_die_;
+ const FilePath original_dir_;
+};
+
+// A class with a member function that may die.
+class MayDie {
+ public:
+ explicit MayDie(bool should_die) : should_die_(should_die) {}
+
+ // A member function that may die.
+ void MemberFunction() const {
+ if (should_die_)
+ DieInside("MayDie::MemberFunction");
+ }
+
+ private:
+ // True iff MemberFunction() should die.
+ bool should_die_;
+};
+
+// A global function that's expected to die.
+void GlobalFunction() { DieInside("GlobalFunction"); }
+
+// A non-void function that's expected to die.
+int NonVoidFunction() {
+ DieInside("NonVoidFunction");
+ return 1;
+}
+
+// A unary function that may die.
+void DieIf(bool should_die) {
+ if (should_die)
+ DieInside("DieIf");
+}
+
+// A binary function that may die.
+bool DieIfLessThan(int x, int y) {
+ if (x < y) {
+ DieInside("DieIfLessThan");
+ }
+ return true;
+}
+
+// Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture.
+void DeathTestSubroutine() {
+ EXPECT_DEATH(GlobalFunction(), "death.*GlobalFunction");
+ ASSERT_DEATH(GlobalFunction(), "death.*GlobalFunction");
+}
+
+// Death in dbg, not opt.
+int DieInDebugElse12(int* sideeffect) {
+ if (sideeffect) *sideeffect = 12;
+#ifndef NDEBUG
+ DieInside("DieInDebugElse12");
+#endif // NDEBUG
+ return 12;
+}
+
+#if GTEST_OS_WINDOWS
+
+// Tests the ExitedWithCode predicate.
+TEST(ExitStatusPredicateTest, ExitedWithCode) {
+ // On Windows, the process's exit code is the same as its exit status,
+ // so the predicate just compares the its input with its parameter.
+ EXPECT_TRUE(testing::ExitedWithCode(0)(0));
+ EXPECT_TRUE(testing::ExitedWithCode(1)(1));
+ EXPECT_TRUE(testing::ExitedWithCode(42)(42));
+ EXPECT_FALSE(testing::ExitedWithCode(0)(1));
+ EXPECT_FALSE(testing::ExitedWithCode(1)(0));
+}
+
+#else
+
+// Returns the exit status of a process that calls _exit(2) with a
+// given exit code. This is a helper function for the
+// ExitStatusPredicateTest test suite.
+static int NormalExitStatus(int exit_code) {
+ pid_t child_pid = fork();
+ if (child_pid == 0) {
+ _exit(exit_code);
+ }
+ int status;
+ waitpid(child_pid, &status, 0);
+ return status;
+}
+
+// Returns the exit status of a process that raises a given signal.
+// If the signal does not cause the process to die, then it returns
+// instead the exit status of a process that exits normally with exit
+// code 1. This is a helper function for the ExitStatusPredicateTest
+// test suite.
+static int KilledExitStatus(int signum) {
+ pid_t child_pid = fork();
+ if (child_pid == 0) {
+ raise(signum);
+ _exit(1);
+ }
+ int status;
+ waitpid(child_pid, &status, 0);
+ return status;
+}
+
+// Tests the ExitedWithCode predicate.
+TEST(ExitStatusPredicateTest, ExitedWithCode) {
+ const int status0 = NormalExitStatus(0);
+ const int status1 = NormalExitStatus(1);
+ const int status42 = NormalExitStatus(42);
+ const testing::ExitedWithCode pred0(0);
+ const testing::ExitedWithCode pred1(1);
+ const testing::ExitedWithCode pred42(42);
+ EXPECT_PRED1(pred0, status0);
+ EXPECT_PRED1(pred1, status1);
+ EXPECT_PRED1(pred42, status42);
+ EXPECT_FALSE(pred0(status1));
+ EXPECT_FALSE(pred42(status0));
+ EXPECT_FALSE(pred1(status42));
+}
+
+// Tests the KilledBySignal predicate.
+TEST(ExitStatusPredicateTest, KilledBySignal) {
+ const int status_segv = KilledExitStatus(SIGSEGV);
+ const int status_kill = KilledExitStatus(SIGKILL);
+ const testing::KilledBySignal pred_segv(SIGSEGV);
+ const testing::KilledBySignal pred_kill(SIGKILL);
+ EXPECT_PRED1(pred_segv, status_segv);
+ EXPECT_PRED1(pred_kill, status_kill);
+ EXPECT_FALSE(pred_segv(status_kill));
+ EXPECT_FALSE(pred_kill(status_segv));
+}
+
+#endif // GTEST_OS_WINDOWS
+
+// Tests that the death test macros expand to code which may or may not
+// be followed by operator<<, and that in either case the complete text
+// comprises only a single C++ statement.
+TEST_F(TestForDeathTest, SingleStatement) {
+ if (AlwaysFalse())
+ // This would fail if executed; this is a compilation test only
+ ASSERT_DEATH(return, "");
+
+ if (AlwaysTrue())
+ EXPECT_DEATH(_exit(1), "");
+ else
+ // This empty "else" branch is meant to ensure that EXPECT_DEATH
+ // doesn't expand into an "if" statement without an "else"
+ ;
+
+ if (AlwaysFalse())
+ ASSERT_DEATH(return, "") << "did not die";
+
+ if (AlwaysFalse())
+ ;
+ else
+ EXPECT_DEATH(_exit(1), "") << 1 << 2 << 3;
+}
+
+void DieWithEmbeddedNul() {
+ fprintf(stderr, "Hello%cmy null world.\n", '\0');
+ fflush(stderr);
+ _exit(1);
+}
+
+#if GTEST_USES_PCRE
+// Tests that EXPECT_DEATH and ASSERT_DEATH work when the error
+// message has a NUL character in it.
+TEST_F(TestForDeathTest, EmbeddedNulInMessage) {
+ // TODO(wan@google.com): <regex.h> doesn't support matching strings
+ // with embedded NUL characters - find a way to workaround it.
+ EXPECT_DEATH(DieWithEmbeddedNul(), "my null world");
+ ASSERT_DEATH(DieWithEmbeddedNul(), "my null world");
+}
+#endif // GTEST_USES_PCRE
+
+// Tests that death test macros expand to code which interacts well with switch
+// statements.
+TEST_F(TestForDeathTest, SwitchStatement) {
+// Microsoft compiler usually complains about switch statements without
+// case labels. We suppress that warning for this test.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4065)
+#endif // _MSC_VER
+
+ switch (0)
+ default:
+ ASSERT_DEATH(_exit(1), "") << "exit in default switch handler";
+
+ switch (0)
+ case 0:
+ EXPECT_DEATH(_exit(1), "") << "exit in switch case";
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+}
+
+// Tests that a static member function can be used in a "fast" style
+// death test.
+TEST_F(TestForDeathTest, StaticMemberFunctionFastStyle) {
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember");
+}
+
+// Tests that a method of the test fixture can be used in a "fast"
+// style death test.
+TEST_F(TestForDeathTest, MemberFunctionFastStyle) {
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ should_die_ = true;
+ EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction");
+}
+
+void ChangeToRootDir() { posix::ChDir(GTEST_PATH_SEP_); }
+
+// Tests that death tests work even if the current directory has been
+// changed.
+TEST_F(TestForDeathTest, FastDeathTestInChangedDir) {
+ testing::GTEST_FLAG(death_test_style) = "fast";
+
+ ChangeToRootDir();
+ EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), "");
+
+ ChangeToRootDir();
+ ASSERT_DEATH(_exit(1), "");
+}
+
+// Repeats a representative sample of death tests in the "threadsafe" style:
+
+TEST_F(TestForDeathTest, StaticMemberFunctionThreadsafeStyle) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ ASSERT_DEATH(StaticMemberFunction(), "death.*StaticMember");
+}
+
+TEST_F(TestForDeathTest, MemberFunctionThreadsafeStyle) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ should_die_ = true;
+ EXPECT_DEATH(MemberFunction(), "inside.*MemberFunction");
+}
+
+TEST_F(TestForDeathTest, ThreadsafeDeathTestInLoop) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+
+ for (int i = 0; i < 3; ++i)
+ EXPECT_EXIT(_exit(i), testing::ExitedWithCode(i), "") << ": i = " << i;
+}
+
+TEST_F(TestForDeathTest, ThreadsafeDeathTestInChangedDir) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+
+ ChangeToRootDir();
+ EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), "");
+
+ ChangeToRootDir();
+ ASSERT_DEATH(_exit(1), "");
+}
+
+TEST_F(TestForDeathTest, MixedStyles) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ EXPECT_DEATH(_exit(1), "");
+ testing::GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_DEATH(_exit(1), "");
+}
+
+namespace {
+
+bool pthread_flag;
+
+void SetPthreadFlag() {
+ pthread_flag = true;
+}
+
+} // namespace
+
+#if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD
+
+TEST_F(TestForDeathTest, DoesNotExecuteAtforkHooks) {
+ if (!testing::GTEST_FLAG(death_test_use_fork)) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
+ pthread_flag = false;
+ ASSERT_EQ(0, pthread_atfork(&SetPthreadFlag, NULL, NULL));
+ ASSERT_DEATH(_exit(1), "");
+ ASSERT_FALSE(pthread_flag);
+ }
+}
+
+#endif // GTEST_HAS_CLONE && GTEST_HAS_PTHREAD
+
+// Tests that a method of another class can be used in a death test.
+TEST_F(TestForDeathTest, MethodOfAnotherClass) {
+ const MayDie x(true);
+ ASSERT_DEATH(x.MemberFunction(), "MayDie\\:\\:MemberFunction");
+}
+
+// Tests that a global function can be used in a death test.
+TEST_F(TestForDeathTest, GlobalFunction) {
+ EXPECT_DEATH(GlobalFunction(), "GlobalFunction");
+}
+
+// Tests that any value convertible to an RE works as a second
+// argument to EXPECT_DEATH.
+TEST_F(TestForDeathTest, AcceptsAnythingConvertibleToRE) {
+ static const char regex_c_str[] = "GlobalFunction";
+ EXPECT_DEATH(GlobalFunction(), regex_c_str);
+
+ const testing::internal::RE regex(regex_c_str);
+ EXPECT_DEATH(GlobalFunction(), regex);
+
+#if GTEST_HAS_GLOBAL_STRING
+ const string regex_str(regex_c_str);
+ EXPECT_DEATH(GlobalFunction(), regex_str);
+#endif // GTEST_HAS_GLOBAL_STRING
+
+ const ::std::string regex_std_str(regex_c_str);
+ EXPECT_DEATH(GlobalFunction(), regex_std_str);
+}
+
+// Tests that a non-void function can be used in a death test.
+TEST_F(TestForDeathTest, NonVoidFunction) {
+ ASSERT_DEATH(NonVoidFunction(), "NonVoidFunction");
+}
+
+// Tests that functions that take parameter(s) can be used in a death test.
+TEST_F(TestForDeathTest, FunctionWithParameter) {
+ EXPECT_DEATH(DieIf(true), "DieIf\\(\\)");
+ EXPECT_DEATH(DieIfLessThan(2, 3), "DieIfLessThan");
+}
+
+// Tests that ASSERT_DEATH can be used outside a TEST, TEST_F, or test fixture.
+TEST_F(TestForDeathTest, OutsideFixture) {
+ DeathTestSubroutine();
+}
+
+// Tests that death tests can be done inside a loop.
+TEST_F(TestForDeathTest, InsideLoop) {
+ for (int i = 0; i < 5; i++) {
+ EXPECT_DEATH(DieIfLessThan(-1, i), "DieIfLessThan") << "where i == " << i;
+ }
+}
+
+// Tests that a compound statement can be used in a death test.
+TEST_F(TestForDeathTest, CompoundStatement) {
+ EXPECT_DEATH({ // NOLINT
+ const int x = 2;
+ const int y = x + 1;
+ DieIfLessThan(x, y);
+ },
+ "DieIfLessThan");
+}
+
+// Tests that code that doesn't die causes a death test to fail.
+TEST_F(TestForDeathTest, DoesNotDie) {
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(DieIf(false), "DieIf"),
+ "failed to die");
+}
+
+// Tests that a death test fails when the error message isn't expected.
+TEST_F(TestForDeathTest, ErrorMessageMismatch) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_DEATH(DieIf(true), "DieIfLessThan") << "End of death test message.";
+ }, "died but not with expected error");
+}
+
+// On exit, *aborted will be true iff the EXPECT_DEATH() statement
+// aborted the function.
+void ExpectDeathTestHelper(bool* aborted) {
+ *aborted = true;
+ EXPECT_DEATH(DieIf(false), "DieIf"); // This assertion should fail.
+ *aborted = false;
+}
+
+// Tests that EXPECT_DEATH doesn't abort the test on failure.
+TEST_F(TestForDeathTest, EXPECT_DEATH) {
+ bool aborted = true;
+ EXPECT_NONFATAL_FAILURE(ExpectDeathTestHelper(&aborted),
+ "failed to die");
+ EXPECT_FALSE(aborted);
+}
+
+// Tests that ASSERT_DEATH does abort the test on failure.
+TEST_F(TestForDeathTest, ASSERT_DEATH) {
+ static bool aborted;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ aborted = true;
+ ASSERT_DEATH(DieIf(false), "DieIf"); // This assertion should fail.
+ aborted = false;
+ }, "failed to die");
+ EXPECT_TRUE(aborted);
+}
+
+// Tests that EXPECT_DEATH evaluates the arguments exactly once.
+TEST_F(TestForDeathTest, SingleEvaluation) {
+ int x = 3;
+ EXPECT_DEATH(DieIf((++x) == 4), "DieIf");
+
+ const char* regex = "DieIf";
+ const char* regex_save = regex;
+ EXPECT_DEATH(DieIfLessThan(3, 4), regex++);
+ EXPECT_EQ(regex_save + 1, regex);
+}
+
+// Tests that run-away death tests are reported as failures.
+TEST_F(TestForDeathTest, Runaway) {
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(static_cast<void>(0), "Foo"),
+ "failed to die.");
+
+ EXPECT_FATAL_FAILURE(ASSERT_DEATH(return, "Bar"),
+ "illegal return in test statement.");
+}
+
+
+// Tests that EXPECT_DEBUG_DEATH works as expected,
+// that is, in debug mode, it:
+// 1. Asserts on death.
+// 2. Has no side effect.
+//
+// And in opt mode, it:
+// 1. Has side effects but does not assert.
+TEST_F(TestForDeathTest, TestExpectDebugDeath) {
+ int sideeffect = 0;
+
+ EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect),
+ "death.*DieInDebugElse12");
+
+#ifdef NDEBUG
+ // Checks that the assignment occurs in opt mode (sideeffect).
+ EXPECT_EQ(12, sideeffect);
+#else
+ // Checks that the assignment does not occur in dbg mode (no sideeffect).
+ EXPECT_EQ(0, sideeffect);
+#endif
+}
+
+// Tests that ASSERT_DEBUG_DEATH works as expected
+// In debug mode:
+// 1. Asserts on debug death.
+// 2. Has no side effect.
+//
+// In opt mode:
+// 1. Has side effects and returns the expected value (12).
+TEST_F(TestForDeathTest, TestAssertDebugDeath) {
+ int sideeffect = 0;
+
+ ASSERT_DEBUG_DEATH({ // NOLINT
+ // Tests that the return value is 12 in opt mode.
+ EXPECT_EQ(12, DieInDebugElse12(&sideeffect));
+ // Tests that the side effect occurred in opt mode.
+ EXPECT_EQ(12, sideeffect);
+ }, "death.*DieInDebugElse12");
+
+#ifdef NDEBUG
+ // Checks that the assignment occurs in opt mode (sideeffect).
+ EXPECT_EQ(12, sideeffect);
+#else
+ // Checks that the assignment does not occur in dbg mode (no sideeffect).
+ EXPECT_EQ(0, sideeffect);
+#endif
+}
+
+#ifndef NDEBUG
+
+void ExpectDebugDeathHelper(bool* aborted) {
+ *aborted = true;
+ EXPECT_DEBUG_DEATH(return, "") << "This is expected to fail.";
+ *aborted = false;
+}
+
+#if GTEST_OS_WINDOWS
+TEST(PopUpDeathTest, DoesNotShowPopUpOnAbort) {
+ printf("This test should be considered failing if it shows "
+ "any pop-up dialogs.\n");
+ fflush(stdout);
+
+ EXPECT_DEATH({
+ testing::GTEST_FLAG(catch_exceptions) = false;
+ abort();
+ }, "");
+}
+
+TEST(PopUpDeathTest, DoesNotShowPopUpOnThrow) {
+ printf("This test should be considered failing if it shows "
+ "any pop-up dialogs.\n");
+ fflush(stdout);
+
+ EXPECT_DEATH({
+ testing::GTEST_FLAG(catch_exceptions) = false;
+ throw 1;
+ }, "");
+}
+#endif // GTEST_OS_WINDOWS
+
+// Tests that EXPECT_DEBUG_DEATH in debug mode does not abort
+// the function.
+TEST_F(TestForDeathTest, ExpectDebugDeathDoesNotAbort) {
+ bool aborted = true;
+ EXPECT_NONFATAL_FAILURE(ExpectDebugDeathHelper(&aborted), "");
+ EXPECT_FALSE(aborted);
+}
+
+void AssertDebugDeathHelper(bool* aborted) {
+ *aborted = true;
+ ASSERT_DEBUG_DEATH(return, "") << "This is expected to fail.";
+ *aborted = false;
+}
+
+// Tests that ASSERT_DEBUG_DEATH in debug mode aborts the function on
+// failure.
+TEST_F(TestForDeathTest, AssertDebugDeathAborts) {
+ static bool aborted;
+ aborted = false;
+ EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), "");
+ EXPECT_TRUE(aborted);
+}
+
+#endif // _NDEBUG
+
+// Tests the *_EXIT family of macros, using a variety of predicates.
+static void TestExitMacros() {
+ EXPECT_EXIT(_exit(1), testing::ExitedWithCode(1), "");
+ ASSERT_EXIT(_exit(42), testing::ExitedWithCode(42), "");
+
+#if GTEST_OS_WINDOWS
+ // Of all signals effects on the process exit code, only those of SIGABRT
+ // are documented on Windows.
+ // See http://msdn.microsoft.com/en-us/library/dwwzkt4c(VS.71).aspx.
+ EXPECT_EXIT(raise(SIGABRT), testing::ExitedWithCode(3), "");
+#else
+ EXPECT_EXIT(raise(SIGKILL), testing::KilledBySignal(SIGKILL), "") << "foo";
+ ASSERT_EXIT(raise(SIGUSR2), testing::KilledBySignal(SIGUSR2), "") << "bar";
+
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_EXIT(_exit(0), testing::KilledBySignal(SIGSEGV), "")
+ << "This failure is expected, too.";
+ }, "This failure is expected, too.");
+#endif // GTEST_OS_WINDOWS
+
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_EXIT(raise(SIGSEGV), testing::ExitedWithCode(0), "")
+ << "This failure is expected.";
+ }, "This failure is expected.");
+}
+
+TEST_F(TestForDeathTest, ExitMacros) {
+ TestExitMacros();
+}
+
+TEST_F(TestForDeathTest, ExitMacrosUsingFork) {
+ testing::GTEST_FLAG(death_test_use_fork) = true;
+ TestExitMacros();
+}
+
+TEST_F(TestForDeathTest, InvalidStyle) {
+ testing::GTEST_FLAG(death_test_style) = "rococo";
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_DEATH(_exit(0), "") << "This failure is expected.";
+ }, "This failure is expected.");
+}
+
+// A DeathTestFactory that returns MockDeathTests.
+class MockDeathTestFactory : public DeathTestFactory {
+ public:
+ MockDeathTestFactory();
+ virtual bool Create(const char* statement,
+ const ::testing::internal::RE* regex,
+ const char* file, int line, DeathTest** test);
+
+ // Sets the parameters for subsequent calls to Create.
+ void SetParameters(bool create, DeathTest::TestRole role,
+ int status, bool passed);
+
+ // Accessors.
+ int AssumeRoleCalls() const { return assume_role_calls_; }
+ int WaitCalls() const { return wait_calls_; }
+ int PassedCalls() const { return passed_args_.size(); }
+ bool PassedArgument(int n) const { return passed_args_[n]; }
+ int AbortCalls() const { return abort_args_.size(); }
+ DeathTest::AbortReason AbortArgument(int n) const {
+ return abort_args_[n];
+ }
+ bool TestDeleted() const { return test_deleted_; }
+
+ private:
+ friend class MockDeathTest;
+ // If true, Create will return a MockDeathTest; otherwise it returns
+ // NULL.
+ bool create_;
+ // The value a MockDeathTest will return from its AssumeRole method.
+ DeathTest::TestRole role_;
+ // The value a MockDeathTest will return from its Wait method.
+ int status_;
+ // The value a MockDeathTest will return from its Passed method.
+ bool passed_;
+
+ // Number of times AssumeRole was called.
+ int assume_role_calls_;
+ // Number of times Wait was called.
+ int wait_calls_;
+ // The arguments to the calls to Passed since the last call to
+ // SetParameters.
+ std::vector<bool> passed_args_;
+ // The arguments to the calls to Abort since the last call to
+ // SetParameters.
+ std::vector<DeathTest::AbortReason> abort_args_;
+ // True if the last MockDeathTest returned by Create has been
+ // deleted.
+ bool test_deleted_;
+};
+
+
+// A DeathTest implementation useful in testing. It returns values set
+// at its creation from its various inherited DeathTest methods, and
+// reports calls to those methods to its parent MockDeathTestFactory
+// object.
+class MockDeathTest : public DeathTest {
+ public:
+ MockDeathTest(MockDeathTestFactory *parent,
+ TestRole role, int status, bool passed) :
+ parent_(parent), role_(role), status_(status), passed_(passed) {
+ }
+ virtual ~MockDeathTest() {
+ parent_->test_deleted_ = true;
+ }
+ virtual TestRole AssumeRole() {
+ ++parent_->assume_role_calls_;
+ return role_;
+ }
+ virtual int Wait() {
+ ++parent_->wait_calls_;
+ return status_;
+ }
+ virtual bool Passed(bool exit_status_ok) {
+ parent_->passed_args_.push_back(exit_status_ok);
+ return passed_;
+ }
+ virtual void Abort(AbortReason reason) {
+ parent_->abort_args_.push_back(reason);
+ }
+ private:
+ MockDeathTestFactory* const parent_;
+ const TestRole role_;
+ const int status_;
+ const bool passed_;
+};
+
+
+// MockDeathTestFactory constructor.
+MockDeathTestFactory::MockDeathTestFactory()
+ : create_(true),
+ role_(DeathTest::OVERSEE_TEST),
+ status_(0),
+ passed_(true),
+ assume_role_calls_(0),
+ wait_calls_(0),
+ passed_args_(),
+ abort_args_() {
+}
+
+
+// Sets the parameters for subsequent calls to Create.
+void MockDeathTestFactory::SetParameters(bool create,
+ DeathTest::TestRole role,
+ int status, bool passed) {
+ create_ = create;
+ role_ = role;
+ status_ = status;
+ passed_ = passed;
+
+ assume_role_calls_ = 0;
+ wait_calls_ = 0;
+ passed_args_.clear();
+ abort_args_.clear();
+}
+
+
+// Sets test to NULL (if create_ is false) or to the address of a new
+// MockDeathTest object with parameters taken from the last call
+// to SetParameters (if create_ is true). Always returns true.
+bool MockDeathTestFactory::Create(const char* /*statement*/,
+ const ::testing::internal::RE* /*regex*/,
+ const char* /*file*/,
+ int /*line*/,
+ DeathTest** test) {
+ test_deleted_ = false;
+ if (create_) {
+ *test = new MockDeathTest(this, role_, status_, passed_);
+ } else {
+ *test = NULL;
+ }
+ return true;
+}
+
+// A test fixture for testing the logic of the GTEST_DEATH_TEST_ macro.
+// It installs a MockDeathTestFactory that is used for the duration
+// of the test case.
+class MacroLogicDeathTest : public testing::Test {
+ protected:
+ static testing::internal::ReplaceDeathTestFactory* replacer_;
+ static MockDeathTestFactory* factory_;
+
+ static void SetUpTestCase() {
+ factory_ = new MockDeathTestFactory;
+ replacer_ = new testing::internal::ReplaceDeathTestFactory(factory_);
+ }
+
+ static void TearDownTestCase() {
+ delete replacer_;
+ replacer_ = NULL;
+ delete factory_;
+ factory_ = NULL;
+ }
+
+ // Runs a death test that breaks the rules by returning. Such a death
+ // test cannot be run directly from a test routine that uses a
+ // MockDeathTest, or the remainder of the routine will not be executed.
+ static void RunReturningDeathTest(bool* flag) {
+ ASSERT_DEATH({ // NOLINT
+ *flag = true;
+ return;
+ }, "");
+ }
+};
+
+testing::internal::ReplaceDeathTestFactory* MacroLogicDeathTest::replacer_
+ = NULL;
+MockDeathTestFactory* MacroLogicDeathTest::factory_ = NULL;
+
+
+// Test that nothing happens when the factory doesn't return a DeathTest:
+TEST_F(MacroLogicDeathTest, NothingHappens) {
+ bool flag = false;
+ factory_->SetParameters(false, DeathTest::OVERSEE_TEST, 0, true);
+ EXPECT_DEATH(flag = true, "");
+ EXPECT_FALSE(flag);
+ EXPECT_EQ(0, factory_->AssumeRoleCalls());
+ EXPECT_EQ(0, factory_->WaitCalls());
+ EXPECT_EQ(0, factory_->PassedCalls());
+ EXPECT_EQ(0, factory_->AbortCalls());
+ EXPECT_FALSE(factory_->TestDeleted());
+}
+
+// Test that the parent process doesn't run the death test code,
+// and that the Passed method returns false when the (simulated)
+// child process exits with status 0:
+TEST_F(MacroLogicDeathTest, ChildExitsSuccessfully) {
+ bool flag = false;
+ factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 0, true);
+ EXPECT_DEATH(flag = true, "");
+ EXPECT_FALSE(flag);
+ EXPECT_EQ(1, factory_->AssumeRoleCalls());
+ EXPECT_EQ(1, factory_->WaitCalls());
+ ASSERT_EQ(1, factory_->PassedCalls());
+ EXPECT_FALSE(factory_->PassedArgument(0));
+ EXPECT_EQ(0, factory_->AbortCalls());
+ EXPECT_TRUE(factory_->TestDeleted());
+}
+
+// Tests that the Passed method was given the argument "true" when
+// the (simulated) child process exits with status 1:
+TEST_F(MacroLogicDeathTest, ChildExitsUnsuccessfully) {
+ bool flag = false;
+ factory_->SetParameters(true, DeathTest::OVERSEE_TEST, 1, true);
+ EXPECT_DEATH(flag = true, "");
+ EXPECT_FALSE(flag);
+ EXPECT_EQ(1, factory_->AssumeRoleCalls());
+ EXPECT_EQ(1, factory_->WaitCalls());
+ ASSERT_EQ(1, factory_->PassedCalls());
+ EXPECT_TRUE(factory_->PassedArgument(0));
+ EXPECT_EQ(0, factory_->AbortCalls());
+ EXPECT_TRUE(factory_->TestDeleted());
+}
+
+// Tests that the (simulated) child process executes the death test
+// code, and is aborted with the correct AbortReason if it
+// executes a return statement.
+TEST_F(MacroLogicDeathTest, ChildPerformsReturn) {
+ bool flag = false;
+ factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true);
+ RunReturningDeathTest(&flag);
+ EXPECT_TRUE(flag);
+ EXPECT_EQ(1, factory_->AssumeRoleCalls());
+ EXPECT_EQ(0, factory_->WaitCalls());
+ EXPECT_EQ(0, factory_->PassedCalls());
+ EXPECT_EQ(1, factory_->AbortCalls());
+ EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT,
+ factory_->AbortArgument(0));
+ EXPECT_TRUE(factory_->TestDeleted());
+}
+
+// Tests that the (simulated) child process is aborted with the
+// correct AbortReason if it does not die.
+TEST_F(MacroLogicDeathTest, ChildDoesNotDie) {
+ bool flag = false;
+ factory_->SetParameters(true, DeathTest::EXECUTE_TEST, 0, true);
+ EXPECT_DEATH(flag = true, "");
+ EXPECT_TRUE(flag);
+ EXPECT_EQ(1, factory_->AssumeRoleCalls());
+ EXPECT_EQ(0, factory_->WaitCalls());
+ EXPECT_EQ(0, factory_->PassedCalls());
+ // This time there are two calls to Abort: one since the test didn't
+ // die, and another from the ReturnSentinel when it's destroyed. The
+ // sentinel normally isn't destroyed if a test doesn't die, since
+ // _exit(2) is called in that case by ForkingDeathTest, but not by
+ // our MockDeathTest.
+ ASSERT_EQ(2, factory_->AbortCalls());
+ EXPECT_EQ(DeathTest::TEST_DID_NOT_DIE,
+ factory_->AbortArgument(0));
+ EXPECT_EQ(DeathTest::TEST_ENCOUNTERED_RETURN_STATEMENT,
+ factory_->AbortArgument(1));
+ EXPECT_TRUE(factory_->TestDeleted());
+}
+
+// Tests that a successful death test does not register a successful
+// test part.
+TEST(SuccessRegistrationDeathTest, NoSuccessPart) {
+ EXPECT_DEATH(_exit(1), "");
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+TEST(StreamingAssertionsDeathTest, DeathTest) {
+ EXPECT_DEATH(_exit(1), "") << "unexpected failure";
+ ASSERT_DEATH(_exit(1), "") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_DEATH(_exit(0), "") << "expected failure";
+ }, "expected failure");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_DEATH(_exit(0), "") << "expected failure";
+ }, "expected failure");
+}
+
+// Tests that GetLastErrnoDescription returns an empty string when the
+// last error is 0 and non-empty string when it is non-zero.
+TEST(GetLastErrnoDescription, GetLastErrnoDescriptionWorks) {
+ errno = ENOENT;
+ EXPECT_STRNE("", GetLastErrnoDescription().c_str());
+ errno = 0;
+ EXPECT_STREQ("", GetLastErrnoDescription().c_str());
+}
+
+#if GTEST_OS_WINDOWS
+TEST(AutoHandleTest, AutoHandleWorks) {
+ HANDLE handle = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+ ASSERT_NE(INVALID_HANDLE_VALUE, handle);
+
+ // Tests that the AutoHandle is correctly initialized with a handle.
+ testing::internal::AutoHandle auto_handle(handle);
+ EXPECT_EQ(handle, auto_handle.Get());
+
+ // Tests that Reset assigns INVALID_HANDLE_VALUE.
+ // Note that this cannot verify whether the original handle is closed.
+ auto_handle.Reset();
+ EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle.Get());
+
+ // Tests that Reset assigns the new handle.
+ // Note that this cannot verify whether the original handle is closed.
+ handle = ::CreateEvent(NULL, FALSE, FALSE, NULL);
+ ASSERT_NE(INVALID_HANDLE_VALUE, handle);
+ auto_handle.Reset(handle);
+ EXPECT_EQ(handle, auto_handle.Get());
+
+ // Tests that AutoHandle contains INVALID_HANDLE_VALUE by default.
+ testing::internal::AutoHandle auto_handle2;
+ EXPECT_EQ(INVALID_HANDLE_VALUE, auto_handle2.Get());
+}
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_OS_WINDOWS
+typedef unsigned __int64 BiggestParsable;
+typedef signed __int64 BiggestSignedParsable;
+const BiggestParsable kBiggestParsableMax = ULLONG_MAX;
+const BiggestParsable kBiggestSignedParsableMax = LLONG_MAX;
+#else
+typedef unsigned long long BiggestParsable;
+typedef signed long long BiggestSignedParsable;
+const BiggestParsable kBiggestParsableMax =
+ ::std::numeric_limits<BiggestParsable>::max();
+const BiggestSignedParsable kBiggestSignedParsableMax =
+ ::std::numeric_limits<BiggestSignedParsable>::max();
+#endif // GTEST_OS_WINDOWS
+
+TEST(ParseNaturalNumberTest, RejectsInvalidFormat) {
+ BiggestParsable result = 0;
+
+ // Rejects non-numbers.
+ EXPECT_FALSE(ParseNaturalNumber(String("non-number string"), &result));
+
+ // Rejects numbers with whitespace prefix.
+ EXPECT_FALSE(ParseNaturalNumber(String(" 123"), &result));
+
+ // Rejects negative numbers.
+ EXPECT_FALSE(ParseNaturalNumber(String("-123"), &result));
+
+ // Rejects numbers starting with a plus sign.
+ EXPECT_FALSE(ParseNaturalNumber(String("+123"), &result));
+ errno = 0;
+}
+
+TEST(ParseNaturalNumberTest, RejectsOverflownNumbers) {
+ BiggestParsable result = 0;
+
+ EXPECT_FALSE(ParseNaturalNumber(String("99999999999999999999999"), &result));
+
+ signed char char_result = 0;
+ EXPECT_FALSE(ParseNaturalNumber(String("200"), &char_result));
+ errno = 0;
+}
+
+TEST(ParseNaturalNumberTest, AcceptsValidNumbers) {
+ BiggestParsable result = 0;
+
+ result = 0;
+ ASSERT_TRUE(ParseNaturalNumber(String("123"), &result));
+ EXPECT_EQ(123U, result);
+
+ // Check 0 as an edge case.
+ result = 1;
+ ASSERT_TRUE(ParseNaturalNumber(String("0"), &result));
+ EXPECT_EQ(0U, result);
+
+ result = 1;
+ ASSERT_TRUE(ParseNaturalNumber(String("00000"), &result));
+ EXPECT_EQ(0U, result);
+}
+
+TEST(ParseNaturalNumberTest, AcceptsTypeLimits) {
+ Message msg;
+ msg << kBiggestParsableMax;
+
+ BiggestParsable result = 0;
+ EXPECT_TRUE(ParseNaturalNumber(msg.GetString(), &result));
+ EXPECT_EQ(kBiggestParsableMax, result);
+
+ Message msg2;
+ msg2 << kBiggestSignedParsableMax;
+
+ BiggestSignedParsable signed_result = 0;
+ EXPECT_TRUE(ParseNaturalNumber(msg2.GetString(), &signed_result));
+ EXPECT_EQ(kBiggestSignedParsableMax, signed_result);
+
+ Message msg3;
+ msg3 << INT_MAX;
+
+ int int_result = 0;
+ EXPECT_TRUE(ParseNaturalNumber(msg3.GetString(), &int_result));
+ EXPECT_EQ(INT_MAX, int_result);
+
+ Message msg4;
+ msg4 << UINT_MAX;
+
+ unsigned int uint_result = 0;
+ EXPECT_TRUE(ParseNaturalNumber(msg4.GetString(), &uint_result));
+ EXPECT_EQ(UINT_MAX, uint_result);
+}
+
+TEST(ParseNaturalNumberTest, WorksForShorterIntegers) {
+ short short_result = 0;
+ ASSERT_TRUE(ParseNaturalNumber(String("123"), &short_result));
+ EXPECT_EQ(123, short_result);
+
+ signed char char_result = 0;
+ ASSERT_TRUE(ParseNaturalNumber(String("123"), &char_result));
+ EXPECT_EQ(123, char_result);
+}
+
+#if GTEST_OS_WINDOWS
+TEST(EnvironmentTest, HandleFitsIntoSizeT) {
+ // TODO(vladl@google.com): Remove this test after this condition is verified
+ // in a static assertion in gtest-death-test.cc in the function
+ // GetStatusFileDescriptor.
+ ASSERT_TRUE(sizeof(HANDLE) <= sizeof(size_t));
+}
+#endif // GTEST_OS_WINDOWS
+
+// Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED trigger
+// failures when death tests are available on the system.
+TEST(ConditionalDeathMacrosDeathTest, ExpectsDeathWhenDeathTestsAvailable) {
+ EXPECT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestExpectMacro"),
+ "death inside CondDeathTestExpectMacro");
+ ASSERT_DEATH_IF_SUPPORTED(DieInside("CondDeathTestAssertMacro"),
+ "death inside CondDeathTestAssertMacro");
+
+ // Empty statement will not crash, which must trigger a failure.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DEATH_IF_SUPPORTED(;, ""), "");
+ EXPECT_FATAL_FAILURE(ASSERT_DEATH_IF_SUPPORTED(;, ""), "");
+}
+
+#else
+
+using testing::internal::CaptureStderr;
+using testing::internal::GetCapturedStderr;
+using testing::internal::String;
+
+// Tests that EXPECT_DEATH_IF_SUPPORTED/ASSERT_DEATH_IF_SUPPORTED are still
+// defined but do not trigger failures when death tests are not available on
+// the system.
+TEST(ConditionalDeathMacrosTest, WarnsWhenDeathTestsNotAvailable) {
+ // Empty statement will not crash, but that should not trigger a failure
+ // when death tests are not supported.
+ CaptureStderr();
+ EXPECT_DEATH_IF_SUPPORTED(;, "");
+ String output = GetCapturedStderr();
+ ASSERT_TRUE(NULL != strstr(output.c_str(),
+ "Death tests are not supported on this platform"));
+ ASSERT_TRUE(NULL != strstr(output.c_str(), ";"));
+
+ // The streamed message should not be printed as there is no test failure.
+ CaptureStderr();
+ EXPECT_DEATH_IF_SUPPORTED(;, "") << "streamed message";
+ output = GetCapturedStderr();
+ ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message"));
+
+ CaptureStderr();
+ ASSERT_DEATH_IF_SUPPORTED(;, ""); // NOLINT
+ output = GetCapturedStderr();
+ ASSERT_TRUE(NULL != strstr(output.c_str(),
+ "Death tests are not supported on this platform"));
+ ASSERT_TRUE(NULL != strstr(output.c_str(), ";"));
+
+ CaptureStderr();
+ ASSERT_DEATH_IF_SUPPORTED(;, "") << "streamed message"; // NOLINT
+ output = GetCapturedStderr();
+ ASSERT_TRUE(NULL == strstr(output.c_str(), "streamed message"));
+}
+
+void FuncWithAssert(int* n) {
+ ASSERT_DEATH_IF_SUPPORTED(return;, "");
+ (*n)++;
+}
+
+// Tests that ASSERT_DEATH_IF_SUPPORTED does not return from the current
+// function (as ASSERT_DEATH does) if death tests are not supported.
+TEST(ConditionalDeathMacrosTest, AssertDeatDoesNotReturnhIfUnsupported) {
+ int n = 0;
+ FuncWithAssert(&n);
+ EXPECT_EQ(1, n);
+}
+#endif // GTEST_HAS_DEATH_TEST
+
+// Tests that the death test macros expand to code which may or may not
+// be followed by operator<<, and that in either case the complete text
+// comprises only a single C++ statement.
+//
+// The syntax should work whether death tests are available or not.
+TEST(ConditionalDeathMacrosSyntaxDeathTest, SingleStatement) {
+ if (AlwaysFalse())
+ // This would fail if executed; this is a compilation test only
+ ASSERT_DEATH_IF_SUPPORTED(return, "");
+
+ if (AlwaysTrue())
+ EXPECT_DEATH_IF_SUPPORTED(_exit(1), "");
+ else
+ // This empty "else" branch is meant to ensure that EXPECT_DEATH
+ // doesn't expand into an "if" statement without an "else"
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ASSERT_DEATH_IF_SUPPORTED(return, "") << "did not die";
+
+ if (AlwaysFalse())
+ ; // NOLINT
+ else
+ EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << 1 << 2 << 3;
+}
+
+// Tests that conditional death test macros expand to code which interacts
+// well with switch statements.
+TEST(ConditionalDeathMacrosSyntaxDeathTest, SwitchStatement) {
+// Microsoft compiler usually complains about switch statements without
+// case labels. We suppress that warning for this test.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4065)
+#endif // _MSC_VER
+
+ switch (0)
+ default:
+ ASSERT_DEATH_IF_SUPPORTED(_exit(1), "")
+ << "exit in default switch handler";
+
+ switch (0)
+ case 0:
+ EXPECT_DEATH_IF_SUPPORTED(_exit(1), "") << "exit in switch case";
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+}
+
+// Tests that a test case whose name ends with "DeathTest" works fine
+// on Windows.
+TEST(NotADeathTest, Test) {
+ SUCCEED();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest-filepath_test.cc b/Source/ThirdParty/gtest/test/gtest-filepath_test.cc
new file mode 100644
index 000000000..625028275
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-filepath_test.cc
@@ -0,0 +1,690 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray@gmail.com (Keith Ray)
+//
+// Google Test filepath utilities
+//
+// This file tests classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included from gtest_unittest.cc, to avoid changing
+// build or make-files for some existing Google Test clients. Do not
+// #include this file anywhere else!
+
+#include <gtest/internal/gtest-filepath.h>
+#include <gtest/gtest.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_OS_WINDOWS_MOBILE
+#include <windows.h> // NOLINT
+#elif GTEST_OS_WINDOWS
+#include <direct.h> // NOLINT
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+namespace testing {
+namespace internal {
+namespace {
+
+#if GTEST_OS_WINDOWS_MOBILE
+// TODO(wan@google.com): Move these to the POSIX adapter section in
+// gtest-port.h.
+
+// Windows CE doesn't have the remove C function.
+int remove(const char* path) {
+ LPCWSTR wpath = String::AnsiToUtf16(path);
+ int ret = DeleteFile(wpath) ? 0 : -1;
+ delete [] wpath;
+ return ret;
+}
+// Windows CE doesn't have the _rmdir C function.
+int _rmdir(const char* path) {
+ FilePath filepath(path);
+ LPCWSTR wpath = String::AnsiToUtf16(
+ filepath.RemoveTrailingPathSeparator().c_str());
+ int ret = RemoveDirectory(wpath) ? 0 : -1;
+ delete [] wpath;
+ return ret;
+}
+
+#else
+
+TEST(GetCurrentDirTest, ReturnsCurrentDir) {
+ const FilePath original_dir = FilePath::GetCurrentDir();
+ EXPECT_FALSE(original_dir.IsEmpty());
+
+ posix::ChDir(GTEST_PATH_SEP_);
+ const FilePath cwd = FilePath::GetCurrentDir();
+ posix::ChDir(original_dir.c_str());
+
+#if GTEST_OS_WINDOWS
+ // Skips the ":".
+ const char* const cwd_without_drive = strchr(cwd.c_str(), ':');
+ ASSERT_TRUE(cwd_without_drive != NULL);
+ EXPECT_STREQ(GTEST_PATH_SEP_, cwd_without_drive + 1);
+#else
+ EXPECT_STREQ(GTEST_PATH_SEP_, cwd.c_str());
+#endif
+}
+
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+TEST(IsEmptyTest, ReturnsTrueForEmptyPath) {
+ EXPECT_TRUE(FilePath("").IsEmpty());
+ EXPECT_TRUE(FilePath(NULL).IsEmpty());
+}
+
+TEST(IsEmptyTest, ReturnsFalseForNonEmptyPath) {
+ EXPECT_FALSE(FilePath("a").IsEmpty());
+ EXPECT_FALSE(FilePath(".").IsEmpty());
+ EXPECT_FALSE(FilePath("a/b").IsEmpty());
+ EXPECT_FALSE(FilePath("a\\b\\").IsEmpty());
+}
+
+// RemoveDirectoryName "" -> ""
+TEST(RemoveDirectoryNameTest, WhenEmptyName) {
+ EXPECT_STREQ("", FilePath("").RemoveDirectoryName().c_str());
+}
+
+// RemoveDirectoryName "afile" -> "afile"
+TEST(RemoveDirectoryNameTest, ButNoDirectory) {
+ EXPECT_STREQ("afile",
+ FilePath("afile").RemoveDirectoryName().c_str());
+}
+
+// RemoveDirectoryName "/afile" -> "afile"
+TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileName) {
+ EXPECT_STREQ("afile",
+ FilePath(GTEST_PATH_SEP_ "afile").RemoveDirectoryName().c_str());
+}
+
+// RemoveDirectoryName "adir/" -> ""
+TEST(RemoveDirectoryNameTest, WhereThereIsNoFileName) {
+ EXPECT_STREQ("",
+ FilePath("adir" GTEST_PATH_SEP_).RemoveDirectoryName().c_str());
+}
+
+// RemoveDirectoryName "adir/afile" -> "afile"
+TEST(RemoveDirectoryNameTest, ShouldGiveFileName) {
+ EXPECT_STREQ("afile",
+ FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveDirectoryName().c_str());
+}
+
+// RemoveDirectoryName "adir/subdir/afile" -> "afile"
+TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) {
+ EXPECT_STREQ("afile",
+ FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile")
+ .RemoveDirectoryName().c_str());
+}
+
+#if GTEST_HAS_ALT_PATH_SEP_
+
+// Tests that RemoveDirectoryName() works with the alternate separator
+// on Windows.
+
+// RemoveDirectoryName("/afile") -> "afile"
+TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileNameForAlternateSeparator) {
+ EXPECT_STREQ("afile",
+ FilePath("/afile").RemoveDirectoryName().c_str());
+}
+
+// RemoveDirectoryName("adir/") -> ""
+TEST(RemoveDirectoryNameTest, WhereThereIsNoFileNameForAlternateSeparator) {
+ EXPECT_STREQ("",
+ FilePath("adir/").RemoveDirectoryName().c_str());
+}
+
+// RemoveDirectoryName("adir/afile") -> "afile"
+TEST(RemoveDirectoryNameTest, ShouldGiveFileNameForAlternateSeparator) {
+ EXPECT_STREQ("afile",
+ FilePath("adir/afile").RemoveDirectoryName().c_str());
+}
+
+// RemoveDirectoryName("adir/subdir/afile") -> "afile"
+TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileNameForAlternateSeparator) {
+ EXPECT_STREQ("afile",
+ FilePath("adir/subdir/afile").RemoveDirectoryName().c_str());
+}
+
+#endif
+
+// RemoveFileName "" -> "./"
+TEST(RemoveFileNameTest, EmptyName) {
+#if GTEST_OS_WINDOWS_MOBILE
+ // On Windows CE, we use the root as the current directory.
+ EXPECT_STREQ(GTEST_PATH_SEP_,
+ FilePath("").RemoveFileName().c_str());
+#else
+ EXPECT_STREQ("." GTEST_PATH_SEP_,
+ FilePath("").RemoveFileName().c_str());
+#endif
+}
+
+// RemoveFileName "adir/" -> "adir/"
+TEST(RemoveFileNameTest, ButNoFile) {
+ EXPECT_STREQ("adir" GTEST_PATH_SEP_,
+ FilePath("adir" GTEST_PATH_SEP_).RemoveFileName().c_str());
+}
+
+// RemoveFileName "adir/afile" -> "adir/"
+TEST(RemoveFileNameTest, GivesDirName) {
+ EXPECT_STREQ("adir" GTEST_PATH_SEP_,
+ FilePath("adir" GTEST_PATH_SEP_ "afile")
+ .RemoveFileName().c_str());
+}
+
+// RemoveFileName "adir/subdir/afile" -> "adir/subdir/"
+TEST(RemoveFileNameTest, GivesDirAndSubDirName) {
+ EXPECT_STREQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_,
+ FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile")
+ .RemoveFileName().c_str());
+}
+
+// RemoveFileName "/afile" -> "/"
+TEST(RemoveFileNameTest, GivesRootDir) {
+ EXPECT_STREQ(GTEST_PATH_SEP_,
+ FilePath(GTEST_PATH_SEP_ "afile").RemoveFileName().c_str());
+}
+
+#if GTEST_HAS_ALT_PATH_SEP_
+
+// Tests that RemoveFileName() works with the alternate separator on
+// Windows.
+
+// RemoveFileName("adir/") -> "adir/"
+TEST(RemoveFileNameTest, ButNoFileForAlternateSeparator) {
+ EXPECT_STREQ("adir" GTEST_PATH_SEP_,
+ FilePath("adir/").RemoveFileName().c_str());
+}
+
+// RemoveFileName("adir/afile") -> "adir/"
+TEST(RemoveFileNameTest, GivesDirNameForAlternateSeparator) {
+ EXPECT_STREQ("adir" GTEST_PATH_SEP_,
+ FilePath("adir/afile").RemoveFileName().c_str());
+}
+
+// RemoveFileName("adir/subdir/afile") -> "adir/subdir/"
+TEST(RemoveFileNameTest, GivesDirAndSubDirNameForAlternateSeparator) {
+ EXPECT_STREQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_,
+ FilePath("adir/subdir/afile").RemoveFileName().c_str());
+}
+
+// RemoveFileName("/afile") -> "\"
+TEST(RemoveFileNameTest, GivesRootDirForAlternateSeparator) {
+ EXPECT_STREQ(GTEST_PATH_SEP_,
+ FilePath("/afile").RemoveFileName().c_str());
+}
+
+#endif
+
+TEST(MakeFileNameTest, GenerateWhenNumberIsZero) {
+ FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"),
+ 0, "xml");
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str());
+}
+
+TEST(MakeFileNameTest, GenerateFileNameNumberGtZero) {
+ FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"),
+ 12, "xml");
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.c_str());
+}
+
+TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberIsZero) {
+ FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_),
+ FilePath("bar"), 0, "xml");
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str());
+}
+
+TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberGtZero) {
+ FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_),
+ FilePath("bar"), 12, "xml");
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.c_str());
+}
+
+TEST(MakeFileNameTest, GenerateWhenNumberIsZeroAndDirIsEmpty) {
+ FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"),
+ 0, "xml");
+ EXPECT_STREQ("bar.xml", actual.c_str());
+}
+
+TEST(MakeFileNameTest, GenerateWhenNumberIsNotZeroAndDirIsEmpty) {
+ FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"),
+ 14, "xml");
+ EXPECT_STREQ("bar_14.xml", actual.c_str());
+}
+
+TEST(ConcatPathsTest, WorksWhenDirDoesNotEndWithPathSep) {
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo"),
+ FilePath("bar.xml"));
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str());
+}
+
+TEST(ConcatPathsTest, WorksWhenPath1EndsWithPathSep) {
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_),
+ FilePath("bar.xml"));
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.c_str());
+}
+
+TEST(ConcatPathsTest, Path1BeingEmpty) {
+ FilePath actual = FilePath::ConcatPaths(FilePath(""),
+ FilePath("bar.xml"));
+ EXPECT_STREQ("bar.xml", actual.c_str());
+}
+
+TEST(ConcatPathsTest, Path2BeingEmpty) {
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo"),
+ FilePath(""));
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_, actual.c_str());
+}
+
+TEST(ConcatPathsTest, BothPathBeingEmpty) {
+ FilePath actual = FilePath::ConcatPaths(FilePath(""),
+ FilePath(""));
+ EXPECT_STREQ("", actual.c_str());
+}
+
+TEST(ConcatPathsTest, Path1ContainsPathSep) {
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_ "bar"),
+ FilePath("foobar.xml"));
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "foobar.xml",
+ actual.c_str());
+}
+
+TEST(ConcatPathsTest, Path2ContainsPathSep) {
+ FilePath actual = FilePath::ConcatPaths(
+ FilePath("foo" GTEST_PATH_SEP_),
+ FilePath("bar" GTEST_PATH_SEP_ "bar.xml"));
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "bar.xml",
+ actual.c_str());
+}
+
+TEST(ConcatPathsTest, Path2EndsWithPathSep) {
+ FilePath actual = FilePath::ConcatPaths(FilePath("foo"),
+ FilePath("bar" GTEST_PATH_SEP_));
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_, actual.c_str());
+}
+
+// RemoveTrailingPathSeparator "" -> ""
+TEST(RemoveTrailingPathSeparatorTest, EmptyString) {
+ EXPECT_STREQ("",
+ FilePath("").RemoveTrailingPathSeparator().c_str());
+}
+
+// RemoveTrailingPathSeparator "foo" -> "foo"
+TEST(RemoveTrailingPathSeparatorTest, FileNoSlashString) {
+ EXPECT_STREQ("foo",
+ FilePath("foo").RemoveTrailingPathSeparator().c_str());
+}
+
+// RemoveTrailingPathSeparator "foo/" -> "foo"
+TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveTrailingSeparator) {
+ EXPECT_STREQ(
+ "foo",
+ FilePath("foo" GTEST_PATH_SEP_).RemoveTrailingPathSeparator().c_str());
+#if GTEST_HAS_ALT_PATH_SEP_
+ EXPECT_STREQ("foo",
+ FilePath("foo/").RemoveTrailingPathSeparator().c_str());
+#endif
+}
+
+// RemoveTrailingPathSeparator "foo/bar/" -> "foo/bar/"
+TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveLastSeparator) {
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_)
+ .RemoveTrailingPathSeparator().c_str());
+}
+
+// RemoveTrailingPathSeparator "foo/bar" -> "foo/bar"
+TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified) {
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ "bar")
+ .RemoveTrailingPathSeparator().c_str());
+}
+
+TEST(DirectoryTest, RootDirectoryExists) {
+#if GTEST_OS_WINDOWS // We are on Windows.
+ char current_drive[_MAX_PATH]; // NOLINT
+ current_drive[0] = static_cast<char>(_getdrive() + 'A' - 1);
+ current_drive[1] = ':';
+ current_drive[2] = '\\';
+ current_drive[3] = '\0';
+ EXPECT_TRUE(FilePath(current_drive).DirectoryExists());
+#else
+ EXPECT_TRUE(FilePath("/").DirectoryExists());
+#endif // GTEST_OS_WINDOWS
+}
+
+#if GTEST_OS_WINDOWS
+TEST(DirectoryTest, RootOfWrongDriveDoesNotExists) {
+ const int saved_drive_ = _getdrive();
+ // Find a drive that doesn't exist. Start with 'Z' to avoid common ones.
+ for (char drive = 'Z'; drive >= 'A'; drive--)
+ if (_chdrive(drive - 'A' + 1) == -1) {
+ char non_drive[_MAX_PATH]; // NOLINT
+ non_drive[0] = drive;
+ non_drive[1] = ':';
+ non_drive[2] = '\\';
+ non_drive[3] = '\0';
+ EXPECT_FALSE(FilePath(non_drive).DirectoryExists());
+ break;
+ }
+ _chdrive(saved_drive_);
+}
+#endif // GTEST_OS_WINDOWS
+
+#if !GTEST_OS_WINDOWS_MOBILE
+// Windows CE _does_ consider an empty directory to exist.
+TEST(DirectoryTest, EmptyPathDirectoryDoesNotExist) {
+ EXPECT_FALSE(FilePath("").DirectoryExists());
+}
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+TEST(DirectoryTest, CurrentDirectoryExists) {
+#if GTEST_OS_WINDOWS // We are on Windows.
+#ifndef _WIN32_CE // Windows CE doesn't have a current directory.
+ EXPECT_TRUE(FilePath(".").DirectoryExists());
+ EXPECT_TRUE(FilePath(".\\").DirectoryExists());
+#endif // _WIN32_CE
+#else
+ EXPECT_TRUE(FilePath(".").DirectoryExists());
+ EXPECT_TRUE(FilePath("./").DirectoryExists());
+#endif // GTEST_OS_WINDOWS
+}
+
+TEST(NormalizeTest, NullStringsEqualEmptyDirectory) {
+ EXPECT_STREQ("", FilePath(NULL).c_str());
+ EXPECT_STREQ("", FilePath(String(NULL)).c_str());
+}
+
+// "foo/bar" == foo//bar" == "foo///bar"
+TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring) {
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ "bar").c_str());
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str());
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_ "bar",
+ FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_
+ GTEST_PATH_SEP_ "bar").c_str());
+}
+
+// "/bar" == //bar" == "///bar"
+TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart) {
+ EXPECT_STREQ(GTEST_PATH_SEP_ "bar",
+ FilePath(GTEST_PATH_SEP_ "bar").c_str());
+ EXPECT_STREQ(GTEST_PATH_SEP_ "bar",
+ FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str());
+ EXPECT_STREQ(GTEST_PATH_SEP_ "bar",
+ FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").c_str());
+}
+
+// "foo/" == foo//" == "foo///"
+TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd) {
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo" GTEST_PATH_SEP_).c_str());
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_).c_str());
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_).c_str());
+}
+
+#if GTEST_HAS_ALT_PATH_SEP_
+
+// Tests that separators at the end of the string are normalized
+// regardless of their combination (e.g. "foo\" =="foo/\" ==
+// "foo\\/").
+TEST(NormalizeTest, MixAlternateSeparatorAtStringEnd) {
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo/").c_str());
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo" GTEST_PATH_SEP_ "/").c_str());
+ EXPECT_STREQ("foo" GTEST_PATH_SEP_,
+ FilePath("foo//" GTEST_PATH_SEP_).c_str());
+}
+
+#endif
+
+TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault) {
+ FilePath default_path;
+ FilePath non_default_path("path");
+ non_default_path = default_path;
+ EXPECT_STREQ("", non_default_path.c_str());
+ EXPECT_STREQ("", default_path.c_str()); // RHS var is unchanged.
+}
+
+TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault) {
+ FilePath non_default_path("path");
+ FilePath default_path;
+ default_path = non_default_path;
+ EXPECT_STREQ("path", default_path.c_str());
+ EXPECT_STREQ("path", non_default_path.c_str()); // RHS var is unchanged.
+}
+
+TEST(AssignmentOperatorTest, ConstAssignedToNonConst) {
+ const FilePath const_default_path("const_path");
+ FilePath non_default_path("path");
+ non_default_path = const_default_path;
+ EXPECT_STREQ("const_path", non_default_path.c_str());
+}
+
+class DirectoryCreationTest : public Test {
+ protected:
+ virtual void SetUp() {
+ testdata_path_.Set(FilePath(String::Format("%s%s%s",
+ TempDir().c_str(), GetCurrentExecutableName().c_str(),
+ "_directory_creation" GTEST_PATH_SEP_ "test" GTEST_PATH_SEP_)));
+ testdata_file_.Set(testdata_path_.RemoveTrailingPathSeparator());
+
+ unique_file0_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"),
+ 0, "txt"));
+ unique_file1_.Set(FilePath::MakeFileName(testdata_path_, FilePath("unique"),
+ 1, "txt"));
+
+ remove(testdata_file_.c_str());
+ remove(unique_file0_.c_str());
+ remove(unique_file1_.c_str());
+ posix::RmDir(testdata_path_.c_str());
+ }
+
+ virtual void TearDown() {
+ remove(testdata_file_.c_str());
+ remove(unique_file0_.c_str());
+ remove(unique_file1_.c_str());
+ posix::RmDir(testdata_path_.c_str());
+ }
+
+ String TempDir() const {
+#if GTEST_OS_WINDOWS_MOBILE
+ return String("\\temp\\");
+#elif GTEST_OS_WINDOWS
+ const char* temp_dir = posix::GetEnv("TEMP");
+ if (temp_dir == NULL || temp_dir[0] == '\0')
+ return String("\\temp\\");
+ else if (String(temp_dir).EndsWith("\\"))
+ return String(temp_dir);
+ else
+ return String::Format("%s\\", temp_dir);
+#else
+ return String("/tmp/");
+#endif // GTEST_OS_WINDOWS_MOBILE
+ }
+
+ void CreateTextFile(const char* filename) {
+ FILE* f = posix::FOpen(filename, "w");
+ fprintf(f, "text\n");
+ fclose(f);
+ }
+
+ // Strings representing a directory and a file, with identical paths
+ // except for the trailing separator character that distinquishes
+ // a directory named 'test' from a file named 'test'. Example names:
+ FilePath testdata_path_; // "/tmp/directory_creation/test/"
+ FilePath testdata_file_; // "/tmp/directory_creation/test"
+ FilePath unique_file0_; // "/tmp/directory_creation/test/unique.txt"
+ FilePath unique_file1_; // "/tmp/directory_creation/test/unique_1.txt"
+};
+
+TEST_F(DirectoryCreationTest, CreateDirectoriesRecursively) {
+ EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.c_str();
+ EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
+ EXPECT_TRUE(testdata_path_.DirectoryExists());
+}
+
+TEST_F(DirectoryCreationTest, CreateDirectoriesForAlreadyExistingPath) {
+ EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.c_str();
+ EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
+ // Call 'create' again... should still succeed.
+ EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively());
+}
+
+TEST_F(DirectoryCreationTest, CreateDirectoriesAndUniqueFilename) {
+ FilePath file_path(FilePath::GenerateUniqueFileName(testdata_path_,
+ FilePath("unique"), "txt"));
+ EXPECT_STREQ(unique_file0_.c_str(), file_path.c_str());
+ EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file not there
+
+ testdata_path_.CreateDirectoriesRecursively();
+ EXPECT_FALSE(file_path.FileOrDirectoryExists()); // file still not there
+ CreateTextFile(file_path.c_str());
+ EXPECT_TRUE(file_path.FileOrDirectoryExists());
+
+ FilePath file_path2(FilePath::GenerateUniqueFileName(testdata_path_,
+ FilePath("unique"), "txt"));
+ EXPECT_STREQ(unique_file1_.c_str(), file_path2.c_str());
+ EXPECT_FALSE(file_path2.FileOrDirectoryExists()); // file not there
+ CreateTextFile(file_path2.c_str());
+ EXPECT_TRUE(file_path2.FileOrDirectoryExists());
+}
+
+TEST_F(DirectoryCreationTest, CreateDirectoriesFail) {
+ // force a failure by putting a file where we will try to create a directory.
+ CreateTextFile(testdata_file_.c_str());
+ EXPECT_TRUE(testdata_file_.FileOrDirectoryExists());
+ EXPECT_FALSE(testdata_file_.DirectoryExists());
+ EXPECT_FALSE(testdata_file_.CreateDirectoriesRecursively());
+}
+
+TEST(NoDirectoryCreationTest, CreateNoDirectoriesForDefaultXmlFile) {
+ const FilePath test_detail_xml("test_detail.xml");
+ EXPECT_FALSE(test_detail_xml.CreateDirectoriesRecursively());
+}
+
+TEST(FilePathTest, DefaultConstructor) {
+ FilePath fp;
+ EXPECT_STREQ("", fp.c_str());
+}
+
+TEST(FilePathTest, CharAndCopyConstructors) {
+ const FilePath fp("spicy");
+ EXPECT_STREQ("spicy", fp.c_str());
+
+ const FilePath fp_copy(fp);
+ EXPECT_STREQ("spicy", fp_copy.c_str());
+}
+
+TEST(FilePathTest, StringConstructor) {
+ const FilePath fp(String("cider"));
+ EXPECT_STREQ("cider", fp.c_str());
+}
+
+TEST(FilePathTest, Set) {
+ const FilePath apple("apple");
+ FilePath mac("mac");
+ mac.Set(apple); // Implement Set() since overloading operator= is forbidden.
+ EXPECT_STREQ("apple", mac.c_str());
+ EXPECT_STREQ("apple", apple.c_str());
+}
+
+TEST(FilePathTest, ToString) {
+ const FilePath file("drink");
+ String str(file.ToString());
+ EXPECT_STREQ("drink", str.c_str());
+}
+
+TEST(FilePathTest, RemoveExtension) {
+ EXPECT_STREQ("app", FilePath("app.exe").RemoveExtension("exe").c_str());
+ EXPECT_STREQ("APP", FilePath("APP.EXE").RemoveExtension("exe").c_str());
+}
+
+TEST(FilePathTest, RemoveExtensionWhenThereIsNoExtension) {
+ EXPECT_STREQ("app", FilePath("app").RemoveExtension("exe").c_str());
+}
+
+TEST(FilePathTest, IsDirectory) {
+ EXPECT_FALSE(FilePath("cola").IsDirectory());
+ EXPECT_TRUE(FilePath("koala" GTEST_PATH_SEP_).IsDirectory());
+#if GTEST_HAS_ALT_PATH_SEP_
+ EXPECT_TRUE(FilePath("koala/").IsDirectory());
+#endif
+}
+
+TEST(FilePathTest, IsAbsolutePath) {
+ EXPECT_FALSE(FilePath("is" GTEST_PATH_SEP_ "relative").IsAbsolutePath());
+ EXPECT_FALSE(FilePath("").IsAbsolutePath());
+#if GTEST_OS_WINDOWS
+ EXPECT_TRUE(FilePath("c:\\" GTEST_PATH_SEP_ "is_not"
+ GTEST_PATH_SEP_ "relative").IsAbsolutePath());
+ EXPECT_FALSE(FilePath("c:foo" GTEST_PATH_SEP_ "bar").IsAbsolutePath());
+ EXPECT_TRUE(FilePath("c:/" GTEST_PATH_SEP_ "is_not"
+ GTEST_PATH_SEP_ "relative").IsAbsolutePath());
+#else
+ EXPECT_TRUE(FilePath(GTEST_PATH_SEP_ "is_not" GTEST_PATH_SEP_ "relative")
+ .IsAbsolutePath());
+#endif // GTEST_OS_WINDOWS
+}
+
+TEST(FilePathTest, IsRootDirectory) {
+#if GTEST_OS_WINDOWS
+ EXPECT_TRUE(FilePath("a:\\").IsRootDirectory());
+ EXPECT_TRUE(FilePath("Z:/").IsRootDirectory());
+ EXPECT_TRUE(FilePath("e://").IsRootDirectory());
+ EXPECT_FALSE(FilePath("").IsRootDirectory());
+ EXPECT_FALSE(FilePath("b:").IsRootDirectory());
+ EXPECT_FALSE(FilePath("b:a").IsRootDirectory());
+ EXPECT_FALSE(FilePath("8:/").IsRootDirectory());
+ EXPECT_FALSE(FilePath("c|/").IsRootDirectory());
+#else
+ EXPECT_TRUE(FilePath("/").IsRootDirectory());
+ EXPECT_TRUE(FilePath("//").IsRootDirectory());
+ EXPECT_FALSE(FilePath("").IsRootDirectory());
+ EXPECT_FALSE(FilePath("\\").IsRootDirectory());
+ EXPECT_FALSE(FilePath("/x").IsRootDirectory());
+#endif
+}
+
+} // namespace
+} // namespace internal
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/test/gtest-linked_ptr_test.cc b/Source/ThirdParty/gtest/test/gtest-linked_ptr_test.cc
new file mode 100644
index 000000000..eae82296c
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-linked_ptr_test.cc
@@ -0,0 +1,154 @@
+// Copyright 2003, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Dan Egnor (egnor@google.com)
+// Ported to Windows: Vadim Berman (vadimb@google.com)
+
+#include <gtest/internal/gtest-linked_ptr.h>
+
+#include <stdlib.h>
+#include <gtest/gtest.h>
+
+namespace {
+
+using testing::Message;
+using testing::internal::linked_ptr;
+
+int num;
+Message* history = NULL;
+
+// Class which tracks allocation/deallocation
+class A {
+ public:
+ A(): mynum(num++) { *history << "A" << mynum << " ctor\n"; }
+ virtual ~A() { *history << "A" << mynum << " dtor\n"; }
+ virtual void Use() { *history << "A" << mynum << " use\n"; }
+ protected:
+ int mynum;
+};
+
+// Subclass
+class B : public A {
+ public:
+ B() { *history << "B" << mynum << " ctor\n"; }
+ ~B() { *history << "B" << mynum << " dtor\n"; }
+ virtual void Use() { *history << "B" << mynum << " use\n"; }
+};
+
+class LinkedPtrTest : public testing::Test {
+ public:
+ LinkedPtrTest() {
+ num = 0;
+ history = new Message;
+ }
+
+ virtual ~LinkedPtrTest() {
+ delete history;
+ history = NULL;
+ }
+};
+
+TEST_F(LinkedPtrTest, GeneralTest) {
+ {
+ linked_ptr<A> a0, a1, a2;
+ a0 = a0;
+ a1 = a2;
+ ASSERT_EQ(a0.get(), static_cast<A*>(NULL));
+ ASSERT_EQ(a1.get(), static_cast<A*>(NULL));
+ ASSERT_EQ(a2.get(), static_cast<A*>(NULL));
+ ASSERT_TRUE(a0 == NULL);
+ ASSERT_TRUE(a1 == NULL);
+ ASSERT_TRUE(a2 == NULL);
+
+ {
+ linked_ptr<A> a3(new A);
+ a0 = a3;
+ ASSERT_TRUE(a0 == a3);
+ ASSERT_TRUE(a0 != NULL);
+ ASSERT_TRUE(a0.get() == a3);
+ ASSERT_TRUE(a0 == a3.get());
+ linked_ptr<A> a4(a0);
+ a1 = a4;
+ linked_ptr<A> a5(new A);
+ ASSERT_TRUE(a5.get() != a3);
+ ASSERT_TRUE(a5 != a3.get());
+ a2 = a5;
+ linked_ptr<B> b0(new B);
+ linked_ptr<A> a6(b0);
+ ASSERT_TRUE(b0 == a6);
+ ASSERT_TRUE(a6 == b0);
+ ASSERT_TRUE(b0 != NULL);
+ a5 = b0;
+ a5 = b0;
+ a3->Use();
+ a4->Use();
+ a5->Use();
+ a6->Use();
+ b0->Use();
+ (*b0).Use();
+ b0.get()->Use();
+ }
+
+ a0->Use();
+ a1->Use();
+ a2->Use();
+
+ a1 = a2;
+ a2.reset(new A);
+ a0.reset();
+
+ linked_ptr<A> a7;
+ }
+
+ ASSERT_STREQ(
+ "A0 ctor\n"
+ "A1 ctor\n"
+ "A2 ctor\n"
+ "B2 ctor\n"
+ "A0 use\n"
+ "A0 use\n"
+ "B2 use\n"
+ "B2 use\n"
+ "B2 use\n"
+ "B2 use\n"
+ "B2 use\n"
+ "B2 dtor\n"
+ "A2 dtor\n"
+ "A0 use\n"
+ "A0 use\n"
+ "A1 use\n"
+ "A3 ctor\n"
+ "A0 dtor\n"
+ "A3 dtor\n"
+ "A1 dtor\n",
+ history->GetString().c_str()
+ );
+}
+
+} // Unnamed namespace
diff --git a/Source/ThirdParty/gtest/test/gtest-listener_test.cc b/Source/ThirdParty/gtest/test/gtest-listener_test.cc
new file mode 100644
index 000000000..c9be39a87
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-listener_test.cc
@@ -0,0 +1,313 @@
+// Copyright 2009 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This file verifies Google Test event listeners receive events at the
+// right times.
+
+#include <gtest/gtest.h>
+#include <vector>
+
+using ::testing::AddGlobalTestEnvironment;
+using ::testing::Environment;
+using ::testing::InitGoogleTest;
+using ::testing::Test;
+using ::testing::TestCase;
+using ::testing::TestEventListener;
+using ::testing::TestInfo;
+using ::testing::TestPartResult;
+using ::testing::UnitTest;
+using ::testing::internal::String;
+
+// Used by tests to register their events.
+std::vector<String>* g_events = NULL;
+
+namespace testing {
+namespace internal {
+
+class EventRecordingListener : public TestEventListener {
+ public:
+ EventRecordingListener(const char* name) : name_(name) {}
+
+ protected:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnTestProgramStart"));
+ }
+
+ virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int iteration) {
+ Message message;
+ message << GetFullMethodName("OnTestIterationStart")
+ << "(" << iteration << ")";
+ g_events->push_back(message.GetString());
+ }
+
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpStart"));
+ }
+
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnEnvironmentsSetUpEnd"));
+ }
+
+ virtual void OnTestCaseStart(const TestCase& /*test_case*/) {
+ g_events->push_back(GetFullMethodName("OnTestCaseStart"));
+ }
+
+ virtual void OnTestStart(const TestInfo& /*test_info*/) {
+ g_events->push_back(GetFullMethodName("OnTestStart"));
+ }
+
+ virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {
+ g_events->push_back(GetFullMethodName("OnTestPartResult"));
+ }
+
+ virtual void OnTestEnd(const TestInfo& /*test_info*/) {
+ g_events->push_back(GetFullMethodName("OnTestEnd"));
+ }
+
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {
+ g_events->push_back(GetFullMethodName("OnTestCaseEnd"));
+ }
+
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownStart"));
+ }
+
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnEnvironmentsTearDownEnd"));
+ }
+
+ virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int iteration) {
+ Message message;
+ message << GetFullMethodName("OnTestIterationEnd")
+ << "(" << iteration << ")";
+ g_events->push_back(message.GetString());
+ }
+
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {
+ g_events->push_back(GetFullMethodName("OnTestProgramEnd"));
+ }
+
+ private:
+ String GetFullMethodName(const char* name) {
+ Message message;
+ message << name_ << "." << name;
+ return message.GetString();
+ }
+
+ String name_;
+};
+
+class EnvironmentInvocationCatcher : public Environment {
+ protected:
+ virtual void SetUp() {
+ g_events->push_back(String("Environment::SetUp"));
+ }
+
+ virtual void TearDown() {
+ g_events->push_back(String("Environment::TearDown"));
+ }
+};
+
+class ListenerTest : public Test {
+ protected:
+ static void SetUpTestCase() {
+ g_events->push_back(String("ListenerTest::SetUpTestCase"));
+ }
+
+ static void TearDownTestCase() {
+ g_events->push_back(String("ListenerTest::TearDownTestCase"));
+ }
+
+ virtual void SetUp() {
+ g_events->push_back(String("ListenerTest::SetUp"));
+ }
+
+ virtual void TearDown() {
+ g_events->push_back(String("ListenerTest::TearDown"));
+ }
+};
+
+TEST_F(ListenerTest, DoesFoo) {
+ // Test execution order within a test case is not guaranteed so we are not
+ // recording the test name.
+ g_events->push_back(String("ListenerTest::* Test Body"));
+ SUCCEED(); // Triggers OnTestPartResult.
+}
+
+TEST_F(ListenerTest, DoesBar) {
+ g_events->push_back(String("ListenerTest::* Test Body"));
+ SUCCEED(); // Triggers OnTestPartResult.
+}
+
+} // namespace internal
+
+} // namespace testing
+
+using ::testing::internal::EnvironmentInvocationCatcher;
+using ::testing::internal::EventRecordingListener;
+
+void VerifyResults(const std::vector<String>& data,
+ const char* const* expected_data,
+ int expected_data_size) {
+ const int actual_size = data.size();
+ // If the following assertion fails, a new entry will be appended to
+ // data. Hence we save data.size() first.
+ EXPECT_EQ(expected_data_size, actual_size);
+
+ // Compares the common prefix.
+ const int shorter_size = expected_data_size <= actual_size ?
+ expected_data_size : actual_size;
+ int i = 0;
+ for (; i < shorter_size; ++i) {
+ ASSERT_STREQ(expected_data[i], data[i].c_str())
+ << "at position " << i;
+ }
+
+ // Prints extra elements in the actual data.
+ for (; i < actual_size; ++i) {
+ printf(" Actual event #%d: %s\n", i, data[i].c_str());
+ }
+}
+
+int main(int argc, char **argv) {
+ std::vector<String> events;
+ g_events = &events;
+ InitGoogleTest(&argc, argv);
+
+ UnitTest::GetInstance()->listeners().Append(
+ new EventRecordingListener("1st"));
+ UnitTest::GetInstance()->listeners().Append(
+ new EventRecordingListener("2nd"));
+
+ AddGlobalTestEnvironment(new EnvironmentInvocationCatcher);
+
+ GTEST_CHECK_(events.size() == 0)
+ << "AddGlobalTestEnvironment should not generate any events itself.";
+
+ ::testing::GTEST_FLAG(repeat) = 2;
+ int ret_val = RUN_ALL_TESTS();
+
+ const char* const expected_events[] = {
+ "1st.OnTestProgramStart",
+ "2nd.OnTestProgramStart",
+ "1st.OnTestIterationStart(0)",
+ "2nd.OnTestIterationStart(0)",
+ "1st.OnEnvironmentsSetUpStart",
+ "2nd.OnEnvironmentsSetUpStart",
+ "Environment::SetUp",
+ "2nd.OnEnvironmentsSetUpEnd",
+ "1st.OnEnvironmentsSetUpEnd",
+ "1st.OnTestCaseStart",
+ "2nd.OnTestCaseStart",
+ "ListenerTest::SetUpTestCase",
+ "1st.OnTestStart",
+ "2nd.OnTestStart",
+ "ListenerTest::SetUp",
+ "ListenerTest::* Test Body",
+ "1st.OnTestPartResult",
+ "2nd.OnTestPartResult",
+ "ListenerTest::TearDown",
+ "2nd.OnTestEnd",
+ "1st.OnTestEnd",
+ "1st.OnTestStart",
+ "2nd.OnTestStart",
+ "ListenerTest::SetUp",
+ "ListenerTest::* Test Body",
+ "1st.OnTestPartResult",
+ "2nd.OnTestPartResult",
+ "ListenerTest::TearDown",
+ "2nd.OnTestEnd",
+ "1st.OnTestEnd",
+ "ListenerTest::TearDownTestCase",
+ "2nd.OnTestCaseEnd",
+ "1st.OnTestCaseEnd",
+ "1st.OnEnvironmentsTearDownStart",
+ "2nd.OnEnvironmentsTearDownStart",
+ "Environment::TearDown",
+ "2nd.OnEnvironmentsTearDownEnd",
+ "1st.OnEnvironmentsTearDownEnd",
+ "2nd.OnTestIterationEnd(0)",
+ "1st.OnTestIterationEnd(0)",
+ "1st.OnTestIterationStart(1)",
+ "2nd.OnTestIterationStart(1)",
+ "1st.OnEnvironmentsSetUpStart",
+ "2nd.OnEnvironmentsSetUpStart",
+ "Environment::SetUp",
+ "2nd.OnEnvironmentsSetUpEnd",
+ "1st.OnEnvironmentsSetUpEnd",
+ "1st.OnTestCaseStart",
+ "2nd.OnTestCaseStart",
+ "ListenerTest::SetUpTestCase",
+ "1st.OnTestStart",
+ "2nd.OnTestStart",
+ "ListenerTest::SetUp",
+ "ListenerTest::* Test Body",
+ "1st.OnTestPartResult",
+ "2nd.OnTestPartResult",
+ "ListenerTest::TearDown",
+ "2nd.OnTestEnd",
+ "1st.OnTestEnd",
+ "1st.OnTestStart",
+ "2nd.OnTestStart",
+ "ListenerTest::SetUp",
+ "ListenerTest::* Test Body",
+ "1st.OnTestPartResult",
+ "2nd.OnTestPartResult",
+ "ListenerTest::TearDown",
+ "2nd.OnTestEnd",
+ "1st.OnTestEnd",
+ "ListenerTest::TearDownTestCase",
+ "2nd.OnTestCaseEnd",
+ "1st.OnTestCaseEnd",
+ "1st.OnEnvironmentsTearDownStart",
+ "2nd.OnEnvironmentsTearDownStart",
+ "Environment::TearDown",
+ "2nd.OnEnvironmentsTearDownEnd",
+ "1st.OnEnvironmentsTearDownEnd",
+ "2nd.OnTestIterationEnd(1)",
+ "1st.OnTestIterationEnd(1)",
+ "2nd.OnTestProgramEnd",
+ "1st.OnTestProgramEnd"
+ };
+ VerifyResults(events,
+ expected_events,
+ sizeof(expected_events)/sizeof(expected_events[0]));
+
+ // We need to check manually for ad hoc test failures that happen after
+ // RUN_ALL_TESTS finishes.
+ if (UnitTest::GetInstance()->Failed())
+ ret_val = 1;
+
+ return ret_val;
+}
diff --git a/Source/ThirdParty/gtest/test/gtest-message_test.cc b/Source/ThirdParty/gtest/test/gtest-message_test.cc
new file mode 100644
index 000000000..e42b03447
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-message_test.cc
@@ -0,0 +1,167 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Tests for the Message class.
+
+#include <gtest/gtest-message.h>
+
+#include <gtest/gtest.h>
+
+namespace {
+
+using ::testing::Message;
+using ::testing::internal::StrStream;
+
+// A helper function that turns a Message into a C string.
+const char* ToCString(const Message& msg) {
+ static testing::internal::String result;
+ result = msg.GetString();
+ return result.c_str();
+}
+
+// Tests the testing::Message class
+
+// Tests the default constructor.
+TEST(MessageTest, DefaultConstructor) {
+ const Message msg;
+ EXPECT_STREQ("", ToCString(msg));
+}
+
+// Tests the copy constructor.
+TEST(MessageTest, CopyConstructor) {
+ const Message msg1("Hello");
+ const Message msg2(msg1);
+ EXPECT_STREQ("Hello", ToCString(msg2));
+}
+
+// Tests constructing a Message from a C-string.
+TEST(MessageTest, ConstructsFromCString) {
+ Message msg("Hello");
+ EXPECT_STREQ("Hello", ToCString(msg));
+}
+
+// Tests streaming a float.
+TEST(MessageTest, StreamsFloat) {
+ const char* const s = ToCString(Message() << 1.23456F << " " << 2.34567F);
+ // Both numbers should be printed with enough precision.
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "1.234560", s);
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, " 2.345669", s);
+}
+
+// Tests streaming a double.
+TEST(MessageTest, StreamsDouble) {
+ const char* const s = ToCString(Message() << 1260570880.4555497 << " "
+ << 1260572265.1954534);
+ // Both numbers should be printed with enough precision.
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "1260570880.45", s);
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, " 1260572265.19", s);
+}
+
+// Tests streaming a non-char pointer.
+TEST(MessageTest, StreamsPointer) {
+ int n = 0;
+ int* p = &n;
+ EXPECT_STRNE("(null)", ToCString(Message() << p));
+}
+
+// Tests streaming a NULL non-char pointer.
+TEST(MessageTest, StreamsNullPointer) {
+ int* p = NULL;
+ EXPECT_STREQ("(null)", ToCString(Message() << p));
+}
+
+// Tests streaming a C string.
+TEST(MessageTest, StreamsCString) {
+ EXPECT_STREQ("Foo", ToCString(Message() << "Foo"));
+}
+
+// Tests streaming a NULL C string.
+TEST(MessageTest, StreamsNullCString) {
+ char* p = NULL;
+ EXPECT_STREQ("(null)", ToCString(Message() << p));
+}
+
+// Tests streaming std::string.
+TEST(MessageTest, StreamsString) {
+ const ::std::string str("Hello");
+ EXPECT_STREQ("Hello", ToCString(Message() << str));
+}
+
+// Tests that we can output strings containing embedded NULs.
+TEST(MessageTest, StreamsStringWithEmbeddedNUL) {
+ const char char_array_with_nul[] =
+ "Here's a NUL\0 and some more string";
+ const ::std::string string_with_nul(char_array_with_nul,
+ sizeof(char_array_with_nul) - 1);
+ EXPECT_STREQ("Here's a NUL\\0 and some more string",
+ ToCString(Message() << string_with_nul));
+}
+
+// Tests streaming a NUL char.
+TEST(MessageTest, StreamsNULChar) {
+ EXPECT_STREQ("\\0", ToCString(Message() << '\0'));
+}
+
+// Tests streaming int.
+TEST(MessageTest, StreamsInt) {
+ EXPECT_STREQ("123", ToCString(Message() << 123));
+}
+
+// Tests that basic IO manipulators (endl, ends, and flush) can be
+// streamed to Message.
+TEST(MessageTest, StreamsBasicIoManip) {
+ EXPECT_STREQ("Line 1.\nA NUL char \\0 in line 2.",
+ ToCString(Message() << "Line 1." << std::endl
+ << "A NUL char " << std::ends << std::flush
+ << " in line 2."));
+}
+
+// Tests Message::GetString()
+TEST(MessageTest, GetString) {
+ Message msg;
+ msg << 1 << " lamb";
+ EXPECT_STREQ("1 lamb", msg.GetString().c_str());
+}
+
+// Tests streaming a Message object to an ostream.
+TEST(MessageTest, StreamsToOStream) {
+ Message msg("Hello");
+ StrStream ss;
+ ss << msg;
+ EXPECT_STREQ("Hello", testing::internal::StrStreamToString(&ss).c_str());
+}
+
+// Tests that a Message object doesn't take up too much stack space.
+TEST(MessageTest, DoesNotTakeUpMuchStackSpace) {
+ EXPECT_LE(sizeof(Message), 16U);
+}
+
+} // namespace
diff --git a/Source/ThirdParty/gtest/test/gtest-options_test.cc b/Source/ThirdParty/gtest/test/gtest-options_test.cc
new file mode 100644
index 000000000..2e2cbc92e
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-options_test.cc
@@ -0,0 +1,212 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: keith.ray@gmail.com (Keith Ray)
+//
+// Google Test UnitTestOptions tests
+//
+// This file tests classes and functions used internally by
+// Google Test. They are subject to change without notice.
+//
+// This file is #included from gtest.cc, to avoid changing build or
+// make-files on Windows and other platforms. Do not #include this file
+// anywhere else!
+
+#include <gtest/gtest.h>
+
+#if GTEST_OS_WINDOWS_MOBILE
+#include <windows.h>
+#elif GTEST_OS_WINDOWS
+#include <direct.h>
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+namespace internal {
+namespace {
+
+// Turns the given relative path into an absolute path.
+FilePath GetAbsolutePathOf(const FilePath& relative_path) {
+ return FilePath::ConcatPaths(FilePath::GetCurrentDir(), relative_path);
+}
+
+// Testing UnitTestOptions::GetOutputFormat/GetOutputFile.
+
+TEST(XmlOutputTest, GetOutputFormatDefault) {
+ GTEST_FLAG(output) = "";
+ EXPECT_STREQ("", UnitTestOptions::GetOutputFormat().c_str());
+}
+
+TEST(XmlOutputTest, GetOutputFormat) {
+ GTEST_FLAG(output) = "xml:filename";
+ EXPECT_STREQ("xml", UnitTestOptions::GetOutputFormat().c_str());
+}
+
+TEST(XmlOutputTest, GetOutputFileDefault) {
+ GTEST_FLAG(output) = "";
+ EXPECT_STREQ(GetAbsolutePathOf(FilePath("test_detail.xml")).c_str(),
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+}
+
+TEST(XmlOutputTest, GetOutputFileSingleFile) {
+ GTEST_FLAG(output) = "xml:filename.abc";
+ EXPECT_STREQ(GetAbsolutePathOf(FilePath("filename.abc")).c_str(),
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+}
+
+TEST(XmlOutputTest, GetOutputFileFromDirectoryPath) {
+ GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_;
+ const std::string expected_output_file =
+ GetAbsolutePathOf(
+ FilePath(std::string("path") + GTEST_PATH_SEP_ +
+ GetCurrentExecutableName().c_str() + ".xml")).c_str();
+ const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile();
+#if GTEST_OS_WINDOWS
+ EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str());
+#else
+ EXPECT_EQ(expected_output_file, output_file.c_str());
+#endif
+}
+
+TEST(OutputFileHelpersTest, GetCurrentExecutableName) {
+ const std::string exe_str = GetCurrentExecutableName().c_str();
+#if GTEST_OS_WINDOWS
+ const bool success =
+ _strcmpi("gtest-options_test", exe_str.c_str()) == 0 ||
+ _strcmpi("gtest-options-ex_test", exe_str.c_str()) == 0 ||
+ _strcmpi("gtest_all_test", exe_str.c_str()) == 0 ||
+ _strcmpi("gtest_dll_test", exe_str.c_str()) == 0;
+#else
+ // TODO(wan@google.com): remove the hard-coded "lt-" prefix when
+ // Chandler Carruth's libtool replacement is ready.
+ const bool success =
+ exe_str == "gtest-options_test" ||
+ exe_str == "gtest_all_test" ||
+ exe_str == "lt-gtest_all_test" ||
+ exe_str == "gtest_dll_test";
+#endif // GTEST_OS_WINDOWS
+ if (!success)
+ FAIL() << "GetCurrentExecutableName() returns " << exe_str;
+}
+
+class XmlOutputChangeDirTest : public Test {
+ protected:
+ virtual void SetUp() {
+ original_working_dir_ = FilePath::GetCurrentDir();
+ posix::ChDir("..");
+ // This will make the test fail if run from the root directory.
+ EXPECT_STRNE(original_working_dir_.c_str(),
+ FilePath::GetCurrentDir().c_str());
+ }
+
+ virtual void TearDown() {
+ posix::ChDir(original_working_dir_.c_str());
+ }
+
+ FilePath original_working_dir_;
+};
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefault) {
+ GTEST_FLAG(output) = "";
+ EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_,
+ FilePath("test_detail.xml")).c_str(),
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefaultXML) {
+ GTEST_FLAG(output) = "xml";
+ EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_,
+ FilePath("test_detail.xml")).c_str(),
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativeFile) {
+ GTEST_FLAG(output) = "xml:filename.abc";
+ EXPECT_STREQ(FilePath::ConcatPaths(original_working_dir_,
+ FilePath("filename.abc")).c_str(),
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativePath) {
+ GTEST_FLAG(output) = "xml:path" GTEST_PATH_SEP_;
+ const std::string expected_output_file =
+ FilePath::ConcatPaths(
+ original_working_dir_,
+ FilePath(std::string("path") + GTEST_PATH_SEP_ +
+ GetCurrentExecutableName().c_str() + ".xml")).c_str();
+ const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile();
+#if GTEST_OS_WINDOWS
+ EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str());
+#else
+ EXPECT_EQ(expected_output_file, output_file.c_str());
+#endif
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsoluteFile) {
+#if GTEST_OS_WINDOWS
+ GTEST_FLAG(output) = "xml:c:\\tmp\\filename.abc";
+ EXPECT_STREQ(FilePath("c:\\tmp\\filename.abc").c_str(),
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+#else
+ GTEST_FLAG(output) ="xml:/tmp/filename.abc";
+ EXPECT_STREQ(FilePath("/tmp/filename.abc").c_str(),
+ UnitTestOptions::GetAbsolutePathToOutputFile().c_str());
+#endif
+}
+
+TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithAbsolutePath) {
+#if GTEST_OS_WINDOWS
+ const std::string path = "c:\\tmp\\";
+#else
+ const std::string path = "/tmp/";
+#endif
+
+ GTEST_FLAG(output) = "xml:" + path;
+ const std::string expected_output_file =
+ path + GetCurrentExecutableName().c_str() + ".xml";
+ const String& output_file = UnitTestOptions::GetAbsolutePathToOutputFile();
+
+#if GTEST_OS_WINDOWS
+ EXPECT_STRCASEEQ(expected_output_file.c_str(), output_file.c_str());
+#else
+ EXPECT_EQ(expected_output_file, output_file.c_str());
+#endif
+}
+
+} // namespace
+} // namespace internal
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/test/gtest-param-test2_test.cc b/Source/ThirdParty/gtest/test/gtest-param-test2_test.cc
new file mode 100644
index 000000000..ccb6cfac9
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-param-test2_test.cc
@@ -0,0 +1,65 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+//
+// Tests for Google Test itself. This verifies that the basic constructs of
+// Google Test work.
+
+#include <gtest/gtest.h>
+
+#include "test/gtest-param-test_test.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+using ::testing::Values;
+using ::testing::internal::ParamGenerator;
+
+// Tests that generators defined in a different translation unit
+// are functional. The test using extern_gen is defined
+// in gtest-param-test_test.cc.
+ParamGenerator<int> extern_gen = Values(33);
+
+// Tests that a parameterized test case can be defined in one translation unit
+// and instantiated in another. The test is defined in gtest-param-test_test.cc
+// and ExternalInstantiationTest fixture class is defined in
+// gtest-param-test_test.h.
+INSTANTIATE_TEST_CASE_P(MultiplesOf33,
+ ExternalInstantiationTest,
+ Values(33, 66));
+
+// Tests that a parameterized test case can be instantiated
+// in multiple translation units. Another instantiation is defined
+// in gtest-param-test_test.cc and InstantiationInMultipleTranslaionUnitsTest
+// fixture is defined in gtest-param-test_test.h
+INSTANTIATE_TEST_CASE_P(Sequence2,
+ InstantiationInMultipleTranslaionUnitsTest,
+ Values(42*3, 42*4, 42*5));
+
+#endif // GTEST_HAS_PARAM_TEST
diff --git a/Source/ThirdParty/gtest/test/gtest-param-test_test.cc b/Source/ThirdParty/gtest/test/gtest-param-test_test.cc
new file mode 100644
index 000000000..d0a0e735c
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-param-test_test.cc
@@ -0,0 +1,835 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+//
+// Tests for Google Test itself. This file verifies that the parameter
+// generators objects produce correct parameter sequences and that
+// Google Test runtime instantiates correct tests from those sequences.
+
+#include <gtest/gtest.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+#include <algorithm>
+#include <iostream>
+#include <list>
+#include <sstream>
+#include <string>
+#include <vector>
+
+// To include gtest-internal-inl.h.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h" // for UnitTestOptions
+#undef GTEST_IMPLEMENTATION_
+
+#include "test/gtest-param-test_test.h"
+
+using ::std::vector;
+using ::std::sort;
+
+using ::testing::AddGlobalTestEnvironment;
+using ::testing::Bool;
+using ::testing::Message;
+using ::testing::Range;
+using ::testing::TestWithParam;
+using ::testing::Values;
+using ::testing::ValuesIn;
+
+#if GTEST_HAS_COMBINE
+using ::testing::Combine;
+using ::std::tr1::get;
+using ::std::tr1::make_tuple;
+using ::std::tr1::tuple;
+#endif // GTEST_HAS_COMBINE
+
+using ::testing::internal::ParamGenerator;
+using ::testing::internal::UnitTestOptions;
+
+// Prints a value to a string.
+//
+// TODO(wan@google.com): remove PrintValue() when we move matchers and
+// EXPECT_THAT() from Google Mock to Google Test. At that time, we
+// can write EXPECT_THAT(x, Eq(y)) to compare two tuples x and y, as
+// EXPECT_THAT() and the matchers know how to print tuples.
+template <typename T>
+::std::string PrintValue(const T& value) {
+ ::std::stringstream stream;
+ stream << value;
+ return stream.str();
+}
+
+#if GTEST_HAS_COMBINE
+
+// These overloads allow printing tuples in our tests. We cannot
+// define an operator<< for tuples, as that definition needs to be in
+// the std namespace in order to be picked up by Google Test via
+// Argument-Dependent Lookup, yet defining anything in the std
+// namespace in non-STL code is undefined behavior.
+
+template <typename T1, typename T2>
+::std::string PrintValue(const tuple<T1, T2>& value) {
+ ::std::stringstream stream;
+ stream << "(" << get<0>(value) << ", " << get<1>(value) << ")";
+ return stream.str();
+}
+
+template <typename T1, typename T2, typename T3>
+::std::string PrintValue(const tuple<T1, T2, T3>& value) {
+ ::std::stringstream stream;
+ stream << "(" << get<0>(value) << ", " << get<1>(value)
+ << ", "<< get<2>(value) << ")";
+ return stream.str();
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9, typename T10>
+::std::string PrintValue(
+ const tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& value) {
+ ::std::stringstream stream;
+ stream << "(" << get<0>(value) << ", " << get<1>(value)
+ << ", "<< get<2>(value) << ", " << get<3>(value)
+ << ", "<< get<4>(value) << ", " << get<5>(value)
+ << ", "<< get<6>(value) << ", " << get<7>(value)
+ << ", "<< get<8>(value) << ", " << get<9>(value) << ")";
+ return stream.str();
+}
+
+#endif // GTEST_HAS_COMBINE
+
+// Verifies that a sequence generated by the generator and accessed
+// via the iterator object matches the expected one using Google Test
+// assertions.
+template <typename T, size_t N>
+void VerifyGenerator(const ParamGenerator<T>& generator,
+ const T (&expected_values)[N]) {
+ typename ParamGenerator<T>::iterator it = generator.begin();
+ for (size_t i = 0; i < N; ++i) {
+ ASSERT_FALSE(it == generator.end())
+ << "At element " << i << " when accessing via an iterator "
+ << "created with the copy constructor.\n";
+ // We cannot use EXPECT_EQ() here as the values may be tuples,
+ // which don't support <<.
+ EXPECT_TRUE(expected_values[i] == *it)
+ << "where i is " << i
+ << ", expected_values[i] is " << PrintValue(expected_values[i])
+ << ", *it is " << PrintValue(*it)
+ << ", and 'it' is an iterator created with the copy constructor.\n";
+ it++;
+ }
+ EXPECT_TRUE(it == generator.end())
+ << "At the presumed end of sequence when accessing via an iterator "
+ << "created with the copy constructor.\n";
+
+ // Test the iterator assignment. The following lines verify that
+ // the sequence accessed via an iterator initialized via the
+ // assignment operator (as opposed to a copy constructor) matches
+ // just the same.
+ it = generator.begin();
+ for (size_t i = 0; i < N; ++i) {
+ ASSERT_FALSE(it == generator.end())
+ << "At element " << i << " when accessing via an iterator "
+ << "created with the assignment operator.\n";
+ EXPECT_TRUE(expected_values[i] == *it)
+ << "where i is " << i
+ << ", expected_values[i] is " << PrintValue(expected_values[i])
+ << ", *it is " << PrintValue(*it)
+ << ", and 'it' is an iterator created with the copy constructor.\n";
+ it++;
+ }
+ EXPECT_TRUE(it == generator.end())
+ << "At the presumed end of sequence when accessing via an iterator "
+ << "created with the assignment operator.\n";
+}
+
+template <typename T>
+void VerifyGeneratorIsEmpty(const ParamGenerator<T>& generator) {
+ typename ParamGenerator<T>::iterator it = generator.begin();
+ EXPECT_TRUE(it == generator.end());
+
+ it = generator.begin();
+ EXPECT_TRUE(it == generator.end());
+}
+
+// Generator tests. They test that each of the provided generator functions
+// generates an expected sequence of values. The general test pattern
+// instantiates a generator using one of the generator functions,
+// checks the sequence produced by the generator using its iterator API,
+// and then resets the iterator back to the beginning of the sequence
+// and checks the sequence again.
+
+// Tests that iterators produced by generator functions conform to the
+// ForwardIterator concept.
+TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) {
+ const ParamGenerator<int> gen = Range(0, 10);
+ ParamGenerator<int>::iterator it = gen.begin();
+
+ // Verifies that iterator initialization works as expected.
+ ParamGenerator<int>::iterator it2 = it;
+ EXPECT_TRUE(*it == *it2) << "Initialized iterators must point to the "
+ << "element same as its source points to";
+
+ // Verifies that iterator assignment works as expected.
+ it++;
+ EXPECT_FALSE(*it == *it2);
+ it2 = it;
+ EXPECT_TRUE(*it == *it2) << "Assigned iterators must point to the "
+ << "element same as its source points to";
+
+ // Verifies that prefix operator++() returns *this.
+ EXPECT_EQ(&it, &(++it)) << "Result of the prefix operator++ must be "
+ << "refer to the original object";
+
+ // Verifies that the result of the postfix operator++ points to the value
+ // pointed to by the original iterator.
+ int original_value = *it; // Have to compute it outside of macro call to be
+ // unaffected by the parameter evaluation order.
+ EXPECT_EQ(original_value, *(it++));
+
+ // Verifies that prefix and postfix operator++() advance an iterator
+ // all the same.
+ it2 = it;
+ it++;
+ ++it2;
+ EXPECT_TRUE(*it == *it2);
+}
+
+// Tests that Range() generates the expected sequence.
+TEST(RangeTest, IntRangeWithDefaultStep) {
+ const ParamGenerator<int> gen = Range(0, 3);
+ const int expected_values[] = {0, 1, 2};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case. Tests that Range() generates the single element sequence
+// as expected when provided with range limits that are equal.
+TEST(RangeTest, IntRangeSingleValue) {
+ const ParamGenerator<int> gen = Range(0, 1);
+ const int expected_values[] = {0};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case. Tests that Range() with generates empty sequence when
+// supplied with an empty range.
+TEST(RangeTest, IntRangeEmpty) {
+ const ParamGenerator<int> gen = Range(0, 0);
+ VerifyGeneratorIsEmpty(gen);
+}
+
+// Tests that Range() with custom step (greater then one) generates
+// the expected sequence.
+TEST(RangeTest, IntRangeWithCustomStep) {
+ const ParamGenerator<int> gen = Range(0, 9, 3);
+ const int expected_values[] = {0, 3, 6};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that Range() with custom step (greater then one) generates
+// the expected sequence when the last element does not fall on the
+// upper range limit. Sequences generated by Range() must not have
+// elements beyond the range limits.
+TEST(RangeTest, IntRangeWithCustomStepOverUpperBound) {
+ const ParamGenerator<int> gen = Range(0, 4, 3);
+ const int expected_values[] = {0, 3};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Verifies that Range works with user-defined types that define
+// copy constructor, operator=(), operator+(), and operator<().
+class DogAdder {
+ public:
+ explicit DogAdder(const char* a_value) : value_(a_value) {}
+ DogAdder(const DogAdder& other) : value_(other.value_.c_str()) {}
+
+ DogAdder operator=(const DogAdder& other) {
+ if (this != &other)
+ value_ = other.value_;
+ return *this;
+ }
+ DogAdder operator+(const DogAdder& other) const {
+ Message msg;
+ msg << value_.c_str() << other.value_.c_str();
+ return DogAdder(msg.GetString().c_str());
+ }
+ bool operator<(const DogAdder& other) const {
+ return value_ < other.value_;
+ }
+ const ::testing::internal::String& value() const { return value_; }
+
+ private:
+ ::testing::internal::String value_;
+};
+
+TEST(RangeTest, WorksWithACustomType) {
+ const ParamGenerator<DogAdder> gen =
+ Range(DogAdder("cat"), DogAdder("catdogdog"), DogAdder("dog"));
+ ParamGenerator<DogAdder>::iterator it = gen.begin();
+
+ ASSERT_FALSE(it == gen.end());
+ EXPECT_STREQ("cat", it->value().c_str());
+
+ ASSERT_FALSE(++it == gen.end());
+ EXPECT_STREQ("catdog", it->value().c_str());
+
+ EXPECT_TRUE(++it == gen.end());
+}
+
+class IntWrapper {
+ public:
+ explicit IntWrapper(int a_value) : value_(a_value) {}
+ IntWrapper(const IntWrapper& other) : value_(other.value_) {}
+
+ IntWrapper operator=(const IntWrapper& other) {
+ value_ = other.value_;
+ return *this;
+ }
+ // operator+() adds a different type.
+ IntWrapper operator+(int other) const { return IntWrapper(value_ + other); }
+ bool operator<(const IntWrapper& other) const {
+ return value_ < other.value_;
+ }
+ int value() const { return value_; }
+
+ private:
+ int value_;
+};
+
+TEST(RangeTest, WorksWithACustomTypeWithDifferentIncrementType) {
+ const ParamGenerator<IntWrapper> gen = Range(IntWrapper(0), IntWrapper(2));
+ ParamGenerator<IntWrapper>::iterator it = gen.begin();
+
+ ASSERT_FALSE(it == gen.end());
+ EXPECT_EQ(0, it->value());
+
+ ASSERT_FALSE(++it == gen.end());
+ EXPECT_EQ(1, it->value());
+
+ EXPECT_TRUE(++it == gen.end());
+}
+
+// Tests that ValuesIn() with an array parameter generates
+// the expected sequence.
+TEST(ValuesInTest, ValuesInArray) {
+ int array[] = {3, 5, 8};
+ const ParamGenerator<int> gen = ValuesIn(array);
+ VerifyGenerator(gen, array);
+}
+
+// Tests that ValuesIn() with a const array parameter generates
+// the expected sequence.
+TEST(ValuesInTest, ValuesInConstArray) {
+ const int array[] = {3, 5, 8};
+ const ParamGenerator<int> gen = ValuesIn(array);
+ VerifyGenerator(gen, array);
+}
+
+// Edge case. Tests that ValuesIn() with an array parameter containing a
+// single element generates the single element sequence.
+TEST(ValuesInTest, ValuesInSingleElementArray) {
+ int array[] = {42};
+ const ParamGenerator<int> gen = ValuesIn(array);
+ VerifyGenerator(gen, array);
+}
+
+// Tests that ValuesIn() generates the expected sequence for an STL
+// container (vector).
+TEST(ValuesInTest, ValuesInVector) {
+ typedef ::std::vector<int> ContainerType;
+ ContainerType values;
+ values.push_back(3);
+ values.push_back(5);
+ values.push_back(8);
+ const ParamGenerator<int> gen = ValuesIn(values);
+
+ const int expected_values[] = {3, 5, 8};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that ValuesIn() generates the expected sequence.
+TEST(ValuesInTest, ValuesInIteratorRange) {
+ typedef ::std::vector<int> ContainerType;
+ ContainerType values;
+ values.push_back(3);
+ values.push_back(5);
+ values.push_back(8);
+ const ParamGenerator<int> gen = ValuesIn(values.begin(), values.end());
+
+ const int expected_values[] = {3, 5, 8};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case. Tests that ValuesIn() provided with an iterator range specifying a
+// single value generates a single-element sequence.
+TEST(ValuesInTest, ValuesInSingleElementIteratorRange) {
+ typedef ::std::vector<int> ContainerType;
+ ContainerType values;
+ values.push_back(42);
+ const ParamGenerator<int> gen = ValuesIn(values.begin(), values.end());
+
+ const int expected_values[] = {42};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case. Tests that ValuesIn() provided with an empty iterator range
+// generates an empty sequence.
+TEST(ValuesInTest, ValuesInEmptyIteratorRange) {
+ typedef ::std::vector<int> ContainerType;
+ ContainerType values;
+ const ParamGenerator<int> gen = ValuesIn(values.begin(), values.end());
+
+ VerifyGeneratorIsEmpty(gen);
+}
+
+// Tests that the Values() generates the expected sequence.
+TEST(ValuesTest, ValuesWorks) {
+ const ParamGenerator<int> gen = Values(3, 5, 8);
+
+ const int expected_values[] = {3, 5, 8};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that Values() generates the expected sequences from elements of
+// different types convertible to ParamGenerator's parameter type.
+TEST(ValuesTest, ValuesWorksForValuesOfCompatibleTypes) {
+ const ParamGenerator<double> gen = Values(3, 5.0f, 8.0);
+
+ const double expected_values[] = {3.0, 5.0, 8.0};
+ VerifyGenerator(gen, expected_values);
+}
+
+TEST(ValuesTest, ValuesWorksForMaxLengthList) {
+ const ParamGenerator<int> gen = Values(
+ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
+ 110, 120, 130, 140, 150, 160, 170, 180, 190, 200,
+ 210, 220, 230, 240, 250, 260, 270, 280, 290, 300,
+ 310, 320, 330, 340, 350, 360, 370, 380, 390, 400,
+ 410, 420, 430, 440, 450, 460, 470, 480, 490, 500);
+
+ const int expected_values[] = {
+ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100,
+ 110, 120, 130, 140, 150, 160, 170, 180, 190, 200,
+ 210, 220, 230, 240, 250, 260, 270, 280, 290, 300,
+ 310, 320, 330, 340, 350, 360, 370, 380, 390, 400,
+ 410, 420, 430, 440, 450, 460, 470, 480, 490, 500};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Edge case test. Tests that single-parameter Values() generates the sequence
+// with the single value.
+TEST(ValuesTest, ValuesWithSingleParameter) {
+ const ParamGenerator<int> gen = Values(42);
+
+ const int expected_values[] = {42};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that Bool() generates sequence (false, true).
+TEST(BoolTest, BoolWorks) {
+ const ParamGenerator<bool> gen = Bool();
+
+ const bool expected_values[] = {false, true};
+ VerifyGenerator(gen, expected_values);
+}
+
+#if GTEST_HAS_COMBINE
+
+// Tests that Combine() with two parameters generates the expected sequence.
+TEST(CombineTest, CombineWithTwoParameters) {
+ const char* foo = "foo";
+ const char* bar = "bar";
+ const ParamGenerator<tuple<const char*, int> > gen =
+ Combine(Values(foo, bar), Values(3, 4));
+
+ tuple<const char*, int> expected_values[] = {
+ make_tuple(foo, 3), make_tuple(foo, 4),
+ make_tuple(bar, 3), make_tuple(bar, 4)};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that Combine() with three parameters generates the expected sequence.
+TEST(CombineTest, CombineWithThreeParameters) {
+ const ParamGenerator<tuple<int, int, int> > gen = Combine(Values(0, 1),
+ Values(3, 4),
+ Values(5, 6));
+ tuple<int, int, int> expected_values[] = {
+ make_tuple(0, 3, 5), make_tuple(0, 3, 6),
+ make_tuple(0, 4, 5), make_tuple(0, 4, 6),
+ make_tuple(1, 3, 5), make_tuple(1, 3, 6),
+ make_tuple(1, 4, 5), make_tuple(1, 4, 6)};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that the Combine() with the first parameter generating a single value
+// sequence generates a sequence with the number of elements equal to the
+// number of elements in the sequence generated by the second parameter.
+TEST(CombineTest, CombineWithFirstParameterSingleValue) {
+ const ParamGenerator<tuple<int, int> > gen = Combine(Values(42),
+ Values(0, 1));
+
+ tuple<int, int> expected_values[] = {make_tuple(42, 0), make_tuple(42, 1)};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that the Combine() with the second parameter generating a single value
+// sequence generates a sequence with the number of elements equal to the
+// number of elements in the sequence generated by the first parameter.
+TEST(CombineTest, CombineWithSecondParameterSingleValue) {
+ const ParamGenerator<tuple<int, int> > gen = Combine(Values(0, 1),
+ Values(42));
+
+ tuple<int, int> expected_values[] = {make_tuple(0, 42), make_tuple(1, 42)};
+ VerifyGenerator(gen, expected_values);
+}
+
+// Tests that when the first parameter produces an empty sequence,
+// Combine() produces an empty sequence, too.
+TEST(CombineTest, CombineWithFirstParameterEmptyRange) {
+ const ParamGenerator<tuple<int, int> > gen = Combine(Range(0, 0),
+ Values(0, 1));
+ VerifyGeneratorIsEmpty(gen);
+}
+
+// Tests that when the second parameter produces an empty sequence,
+// Combine() produces an empty sequence, too.
+TEST(CombineTest, CombineWithSecondParameterEmptyRange) {
+ const ParamGenerator<tuple<int, int> > gen = Combine(Values(0, 1),
+ Range(1, 1));
+ VerifyGeneratorIsEmpty(gen);
+}
+
+// Edge case. Tests that combine works with the maximum number
+// of parameters supported by Google Test (currently 10).
+TEST(CombineTest, CombineWithMaxNumberOfParameters) {
+ const char* foo = "foo";
+ const char* bar = "bar";
+ const ParamGenerator<tuple<const char*, int, int, int, int, int, int, int,
+ int, int> > gen = Combine(Values(foo, bar),
+ Values(1), Values(2),
+ Values(3), Values(4),
+ Values(5), Values(6),
+ Values(7), Values(8),
+ Values(9));
+
+ tuple<const char*, int, int, int, int, int, int, int, int, int>
+ expected_values[] = {make_tuple(foo, 1, 2, 3, 4, 5, 6, 7, 8, 9),
+ make_tuple(bar, 1, 2, 3, 4, 5, 6, 7, 8, 9)};
+ VerifyGenerator(gen, expected_values);
+}
+
+#endif // GTEST_HAS_COMBINE
+
+// Tests that an generator produces correct sequence after being
+// assigned from another generator.
+TEST(ParamGeneratorTest, AssignmentWorks) {
+ ParamGenerator<int> gen = Values(1, 2);
+ const ParamGenerator<int> gen2 = Values(3, 4);
+ gen = gen2;
+
+ const int expected_values[] = {3, 4};
+ VerifyGenerator(gen, expected_values);
+}
+
+// This test verifies that the tests are expanded and run as specified:
+// one test per element from the sequence produced by the generator
+// specified in INSTANTIATE_TEST_CASE_P. It also verifies that the test's
+// fixture constructor, SetUp(), and TearDown() have run and have been
+// supplied with the correct parameters.
+
+// The use of environment object allows detection of the case where no test
+// case functionality is run at all. In this case TestCaseTearDown will not
+// be able to detect missing tests, naturally.
+template <int kExpectedCalls>
+class TestGenerationEnvironment : public ::testing::Environment {
+ public:
+ static TestGenerationEnvironment* Instance() {
+ static TestGenerationEnvironment* instance = new TestGenerationEnvironment;
+ return instance;
+ }
+
+ void FixtureConstructorExecuted() { fixture_constructor_count_++; }
+ void SetUpExecuted() { set_up_count_++; }
+ void TearDownExecuted() { tear_down_count_++; }
+ void TestBodyExecuted() { test_body_count_++; }
+
+ virtual void TearDown() {
+ // If all MultipleTestGenerationTest tests have been de-selected
+ // by the filter flag, the following checks make no sense.
+ bool perform_check = false;
+
+ for (int i = 0; i < kExpectedCalls; ++i) {
+ Message msg;
+ msg << "TestsExpandedAndRun/" << i;
+ if (UnitTestOptions::FilterMatchesTest(
+ "TestExpansionModule/MultipleTestGenerationTest",
+ msg.GetString().c_str())) {
+ perform_check = true;
+ }
+ }
+ if (perform_check) {
+ EXPECT_EQ(kExpectedCalls, fixture_constructor_count_)
+ << "Fixture constructor of ParamTestGenerationTest test case "
+ << "has not been run as expected.";
+ EXPECT_EQ(kExpectedCalls, set_up_count_)
+ << "Fixture SetUp method of ParamTestGenerationTest test case "
+ << "has not been run as expected.";
+ EXPECT_EQ(kExpectedCalls, tear_down_count_)
+ << "Fixture TearDown method of ParamTestGenerationTest test case "
+ << "has not been run as expected.";
+ EXPECT_EQ(kExpectedCalls, test_body_count_)
+ << "Test in ParamTestGenerationTest test case "
+ << "has not been run as expected.";
+ }
+ }
+ private:
+ TestGenerationEnvironment() : fixture_constructor_count_(0), set_up_count_(0),
+ tear_down_count_(0), test_body_count_(0) {}
+
+ int fixture_constructor_count_;
+ int set_up_count_;
+ int tear_down_count_;
+ int test_body_count_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationEnvironment);
+};
+
+const int test_generation_params[] = {36, 42, 72};
+
+class TestGenerationTest : public TestWithParam<int> {
+ public:
+ enum {
+ PARAMETER_COUNT =
+ sizeof(test_generation_params)/sizeof(test_generation_params[0])
+ };
+
+ typedef TestGenerationEnvironment<PARAMETER_COUNT> Environment;
+
+ TestGenerationTest() {
+ Environment::Instance()->FixtureConstructorExecuted();
+ current_parameter_ = GetParam();
+ }
+ virtual void SetUp() {
+ Environment::Instance()->SetUpExecuted();
+ EXPECT_EQ(current_parameter_, GetParam());
+ }
+ virtual void TearDown() {
+ Environment::Instance()->TearDownExecuted();
+ EXPECT_EQ(current_parameter_, GetParam());
+ }
+
+ static void SetUpTestCase() {
+ bool all_tests_in_test_case_selected = true;
+
+ for (int i = 0; i < PARAMETER_COUNT; ++i) {
+ Message test_name;
+ test_name << "TestsExpandedAndRun/" << i;
+ if ( !UnitTestOptions::FilterMatchesTest(
+ "TestExpansionModule/MultipleTestGenerationTest",
+ test_name.GetString())) {
+ all_tests_in_test_case_selected = false;
+ }
+ }
+ EXPECT_TRUE(all_tests_in_test_case_selected)
+ << "When running the TestGenerationTest test case all of its tests\n"
+ << "must be selected by the filter flag for the test case to pass.\n"
+ << "If not all of them are enabled, we can't reliably conclude\n"
+ << "that the correct number of tests have been generated.";
+
+ collected_parameters_.clear();
+ }
+
+ static void TearDownTestCase() {
+ vector<int> expected_values(test_generation_params,
+ test_generation_params + PARAMETER_COUNT);
+ // Test execution order is not guaranteed by Google Test,
+ // so the order of values in collected_parameters_ can be
+ // different and we have to sort to compare.
+ sort(expected_values.begin(), expected_values.end());
+ sort(collected_parameters_.begin(), collected_parameters_.end());
+
+ EXPECT_TRUE(collected_parameters_ == expected_values);
+ }
+ protected:
+ int current_parameter_;
+ static vector<int> collected_parameters_;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationTest);
+};
+vector<int> TestGenerationTest::collected_parameters_;
+
+TEST_P(TestGenerationTest, TestsExpandedAndRun) {
+ Environment::Instance()->TestBodyExecuted();
+ EXPECT_EQ(current_parameter_, GetParam());
+ collected_parameters_.push_back(GetParam());
+}
+INSTANTIATE_TEST_CASE_P(TestExpansionModule, TestGenerationTest,
+ ValuesIn(test_generation_params));
+
+// This test verifies that the element sequence (third parameter of
+// INSTANTIATE_TEST_CASE_P) is evaluated in InitGoogleTest() and neither at
+// the call site of INSTANTIATE_TEST_CASE_P nor in RUN_ALL_TESTS(). For
+// that, we declare param_value_ to be a static member of
+// GeneratorEvaluationTest and initialize it to 0. We set it to 1 in
+// main(), just before invocation of InitGoogleTest(). After calling
+// InitGoogleTest(), we set the value to 2. If the sequence is evaluated
+// before or after InitGoogleTest, INSTANTIATE_TEST_CASE_P will create a
+// test with parameter other than 1, and the test body will fail the
+// assertion.
+class GeneratorEvaluationTest : public TestWithParam<int> {
+ public:
+ static int param_value() { return param_value_; }
+ static void set_param_value(int param_value) { param_value_ = param_value; }
+
+ private:
+ static int param_value_;
+};
+int GeneratorEvaluationTest::param_value_ = 0;
+
+TEST_P(GeneratorEvaluationTest, GeneratorsEvaluatedInMain) {
+ EXPECT_EQ(1, GetParam());
+}
+INSTANTIATE_TEST_CASE_P(GenEvalModule,
+ GeneratorEvaluationTest,
+ Values(GeneratorEvaluationTest::param_value()));
+
+// Tests that generators defined in a different translation unit are
+// functional. Generator extern_gen is defined in gtest-param-test_test2.cc.
+extern ParamGenerator<int> extern_gen;
+class ExternalGeneratorTest : public TestWithParam<int> {};
+TEST_P(ExternalGeneratorTest, ExternalGenerator) {
+ // Sequence produced by extern_gen contains only a single value
+ // which we verify here.
+ EXPECT_EQ(GetParam(), 33);
+}
+INSTANTIATE_TEST_CASE_P(ExternalGeneratorModule,
+ ExternalGeneratorTest,
+ extern_gen);
+
+// Tests that a parameterized test case can be defined in one translation
+// unit and instantiated in another. This test will be instantiated in
+// gtest-param-test_test2.cc. ExternalInstantiationTest fixture class is
+// defined in gtest-param-test_test.h.
+TEST_P(ExternalInstantiationTest, IsMultipleOf33) {
+ EXPECT_EQ(0, GetParam() % 33);
+}
+
+// Tests that a parameterized test case can be instantiated with multiple
+// generators.
+class MultipleInstantiationTest : public TestWithParam<int> {};
+TEST_P(MultipleInstantiationTest, AllowsMultipleInstances) {
+}
+INSTANTIATE_TEST_CASE_P(Sequence1, MultipleInstantiationTest, Values(1, 2));
+INSTANTIATE_TEST_CASE_P(Sequence2, MultipleInstantiationTest, Range(3, 5));
+
+// Tests that a parameterized test case can be instantiated
+// in multiple translation units. This test will be instantiated
+// here and in gtest-param-test_test2.cc.
+// InstantiationInMultipleTranslationUnitsTest fixture class
+// is defined in gtest-param-test_test.h.
+TEST_P(InstantiationInMultipleTranslaionUnitsTest, IsMultipleOf42) {
+ EXPECT_EQ(0, GetParam() % 42);
+}
+INSTANTIATE_TEST_CASE_P(Sequence1,
+ InstantiationInMultipleTranslaionUnitsTest,
+ Values(42, 42*2));
+
+// Tests that each iteration of parameterized test runs in a separate test
+// object.
+class SeparateInstanceTest : public TestWithParam<int> {
+ public:
+ SeparateInstanceTest() : count_(0) {}
+
+ static void TearDownTestCase() {
+ EXPECT_GE(global_count_, 2)
+ << "If some (but not all) SeparateInstanceTest tests have been "
+ << "filtered out this test will fail. Make sure that all "
+ << "GeneratorEvaluationTest are selected or de-selected together "
+ << "by the test filter.";
+ }
+
+ protected:
+ int count_;
+ static int global_count_;
+};
+int SeparateInstanceTest::global_count_ = 0;
+
+TEST_P(SeparateInstanceTest, TestsRunInSeparateInstances) {
+ EXPECT_EQ(0, count_++);
+ global_count_++;
+}
+INSTANTIATE_TEST_CASE_P(FourElemSequence, SeparateInstanceTest, Range(1, 4));
+
+// Tests that all instantiations of a test have named appropriately. Test
+// defined with TEST_P(TestCaseName, TestName) and instantiated with
+// INSTANTIATE_TEST_CASE_P(SequenceName, TestCaseName, generator) must be named
+// SequenceName/TestCaseName.TestName/i, where i is the 0-based index of the
+// sequence element used to instantiate the test.
+class NamingTest : public TestWithParam<int> {};
+
+TEST_P(NamingTest, TestsAreNamedAppropriately) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ EXPECT_STREQ("ZeroToFiveSequence/NamingTest", test_info->test_case_name());
+
+ Message msg;
+ msg << "TestsAreNamedAppropriately/" << GetParam();
+ EXPECT_STREQ(msg.GetString().c_str(), test_info->name());
+}
+
+INSTANTIATE_TEST_CASE_P(ZeroToFiveSequence, NamingTest, Range(0, 5));
+
+#endif // GTEST_HAS_PARAM_TEST
+
+TEST(CompileTest, CombineIsDefinedOnlyWhenGtestHasParamTestIsDefined) {
+#if GTEST_HAS_COMBINE && !GTEST_HAS_PARAM_TEST
+ FAIL() << "GTEST_HAS_COMBINE is defined while GTEST_HAS_PARAM_TEST is not\n"
+#endif
+}
+
+int main(int argc, char **argv) {
+#if GTEST_HAS_PARAM_TEST
+ // Used in TestGenerationTest test case.
+ AddGlobalTestEnvironment(TestGenerationTest::Environment::Instance());
+ // Used in GeneratorEvaluationTest test case. Tests that the updated value
+ // will be picked up for instantiating tests in GeneratorEvaluationTest.
+ GeneratorEvaluationTest::set_param_value(1);
+#endif // GTEST_HAS_PARAM_TEST
+
+ ::testing::InitGoogleTest(&argc, argv);
+
+#if GTEST_HAS_PARAM_TEST
+ // Used in GeneratorEvaluationTest test case. Tests that value updated
+ // here will NOT be used for instantiating tests in
+ // GeneratorEvaluationTest.
+ GeneratorEvaluationTest::set_param_value(2);
+#endif // GTEST_HAS_PARAM_TEST
+
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest-param-test_test.h b/Source/ThirdParty/gtest/test/gtest-param-test_test.h
new file mode 100644
index 000000000..b7f949361
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-param-test_test.h
@@ -0,0 +1,55 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl@google.com (Vlad Losev)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file provides classes and functions used internally
+// for testing Google Test itself.
+
+#ifndef GTEST_TEST_GTEST_PARAM_TEST_TEST_H_
+#define GTEST_TEST_GTEST_PARAM_TEST_TEST_H_
+
+#include <gtest/gtest.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+// Test fixture for testing definition and instantiation of a test
+// in separate translation units.
+class ExternalInstantiationTest : public ::testing::TestWithParam<int> {};
+
+// Test fixture for testing instantiation of a test in multiple
+// translation units.
+class InstantiationInMultipleTranslaionUnitsTest
+ : public ::testing::TestWithParam<int> {};
+
+#endif // GTEST_HAS_PARAM_TEST
+
+#endif // GTEST_TEST_GTEST_PARAM_TEST_TEST_H_
diff --git a/Source/ThirdParty/gtest/test/gtest-port_test.cc b/Source/ThirdParty/gtest/test/gtest-port_test.cc
new file mode 100644
index 000000000..37258602f
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-port_test.cc
@@ -0,0 +1,1018 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: vladl@google.com (Vlad Losev), wan@google.com (Zhanyong Wan)
+//
+// This file tests the internal cross-platform support utilities.
+
+#include <gtest/internal/gtest-port.h>
+
+#include <stdio.h>
+
+#if GTEST_OS_MAC
+#include <time.h>
+#endif // GTEST_OS_MAC
+
+#include <utility> // For std::pair and std::make_pair.
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+using std::make_pair;
+using std::pair;
+
+namespace testing {
+namespace internal {
+
+// Tests that the element_type typedef is available in scoped_ptr and refers
+// to the parameter type.
+TEST(ScopedPtrTest, DefinesElementType) {
+ StaticAssertTypeEq<int, ::testing::internal::scoped_ptr<int>::element_type>();
+}
+
+// TODO(vladl@google.com): Implement THE REST of scoped_ptr tests.
+
+TEST(GtestCheckSyntaxTest, BehavesLikeASingleStatement) {
+ if (AlwaysFalse())
+ GTEST_CHECK_(false) << "This should never be executed; "
+ "It's a compilation test only.";
+
+ if (AlwaysTrue())
+ GTEST_CHECK_(true);
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ; // NOLINT
+ else
+ GTEST_CHECK_(true) << "";
+}
+
+TEST(GtestCheckSyntaxTest, WorksWithSwitch) {
+ switch (0) {
+ case 1:
+ break;
+ default:
+ GTEST_CHECK_(true);
+ }
+
+ switch(0)
+ case 0:
+ GTEST_CHECK_(true) << "Check failed in switch case";
+}
+
+#if GTEST_OS_MAC
+void* ThreadFunc(void* data) {
+ pthread_mutex_t* mutex = static_cast<pthread_mutex_t*>(data);
+ pthread_mutex_lock(mutex);
+ pthread_mutex_unlock(mutex);
+ return NULL;
+}
+
+TEST(GetThreadCountTest, ReturnsCorrectValue) {
+ EXPECT_EQ(1U, GetThreadCount());
+ pthread_mutex_t mutex;
+ pthread_attr_t attr;
+ pthread_t thread_id;
+
+ // TODO(vladl@google.com): turn mutex into internal::Mutex for automatic
+ // destruction.
+ pthread_mutex_init(&mutex, NULL);
+ pthread_mutex_lock(&mutex);
+ ASSERT_EQ(0, pthread_attr_init(&attr));
+ ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE));
+
+ const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex);
+ ASSERT_EQ(0, pthread_attr_destroy(&attr));
+ ASSERT_EQ(0, status);
+ EXPECT_EQ(2U, GetThreadCount());
+ pthread_mutex_unlock(&mutex);
+
+ void* dummy;
+ ASSERT_EQ(0, pthread_join(thread_id, &dummy));
+
+ // MacOS X may not immediately report the updated thread count after
+ // joining a thread, causing flakiness in this test. To counter that, we
+ // wait for up to .5 seconds for the OS to report the correct value.
+ for (int i = 0; i < 5; ++i) {
+ if (GetThreadCount() == 1)
+ break;
+
+ SleepMilliseconds(100);
+ }
+ EXPECT_EQ(1U, GetThreadCount());
+ pthread_mutex_destroy(&mutex);
+}
+#else
+TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) {
+ EXPECT_EQ(0U, GetThreadCount());
+}
+#endif // GTEST_OS_MAC
+
+TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) {
+ const bool a_false_condition = false;
+ const char regex[] =
+#ifdef _MSC_VER
+ "gtest-port_test\\.cc\\(\\d+\\):"
+#else
+ "gtest-port_test\\.cc:[0-9]+"
+#endif // _MSC_VER
+ ".*a_false_condition.*Extra info.*";
+
+ EXPECT_DEATH_IF_SUPPORTED(GTEST_CHECK_(a_false_condition) << "Extra info",
+ regex);
+}
+
+#if GTEST_HAS_DEATH_TEST
+
+TEST(GtestCheckDeathTest, LivesSilentlyOnSuccess) {
+ EXPECT_EXIT({
+ GTEST_CHECK_(true) << "Extra info";
+ ::std::cerr << "Success\n";
+ exit(0); },
+ ::testing::ExitedWithCode(0), "Success");
+}
+
+#endif // GTEST_HAS_DEATH_TEST
+
+#if GTEST_USES_POSIX_RE
+
+#if GTEST_HAS_TYPED_TEST
+
+template <typename Str>
+class RETest : public ::testing::Test {};
+
+// Defines StringTypes as the list of all string types that class RE
+// supports.
+typedef testing::Types<
+ ::std::string,
+#if GTEST_HAS_GLOBAL_STRING
+ ::string,
+#endif // GTEST_HAS_GLOBAL_STRING
+ const char*> StringTypes;
+
+TYPED_TEST_CASE(RETest, StringTypes);
+
+// Tests RE's implicit constructors.
+TYPED_TEST(RETest, ImplicitConstructorWorks) {
+ const RE empty(TypeParam(""));
+ EXPECT_STREQ("", empty.pattern());
+
+ const RE simple(TypeParam("hello"));
+ EXPECT_STREQ("hello", simple.pattern());
+
+ const RE normal(TypeParam(".*(\\w+)"));
+ EXPECT_STREQ(".*(\\w+)", normal.pattern());
+}
+
+// Tests that RE's constructors reject invalid regular expressions.
+TYPED_TEST(RETest, RejectsInvalidRegex) {
+ EXPECT_NONFATAL_FAILURE({
+ const RE invalid(TypeParam("?"));
+ }, "\"?\" is not a valid POSIX Extended regular expression.");
+}
+
+// Tests RE::FullMatch().
+TYPED_TEST(RETest, FullMatchWorks) {
+ const RE empty(TypeParam(""));
+ EXPECT_TRUE(RE::FullMatch(TypeParam(""), empty));
+ EXPECT_FALSE(RE::FullMatch(TypeParam("a"), empty));
+
+ const RE re(TypeParam("a.*z"));
+ EXPECT_TRUE(RE::FullMatch(TypeParam("az"), re));
+ EXPECT_TRUE(RE::FullMatch(TypeParam("axyz"), re));
+ EXPECT_FALSE(RE::FullMatch(TypeParam("baz"), re));
+ EXPECT_FALSE(RE::FullMatch(TypeParam("azy"), re));
+}
+
+// Tests RE::PartialMatch().
+TYPED_TEST(RETest, PartialMatchWorks) {
+ const RE empty(TypeParam(""));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam(""), empty));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("a"), empty));
+
+ const RE re(TypeParam("a.*z"));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("az"), re));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("axyz"), re));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("baz"), re));
+ EXPECT_TRUE(RE::PartialMatch(TypeParam("azy"), re));
+ EXPECT_FALSE(RE::PartialMatch(TypeParam("zza"), re));
+}
+
+#endif // GTEST_HAS_TYPED_TEST
+
+#elif GTEST_USES_SIMPLE_RE
+
+TEST(IsInSetTest, NulCharIsNotInAnySet) {
+ EXPECT_FALSE(IsInSet('\0', ""));
+ EXPECT_FALSE(IsInSet('\0', "\0"));
+ EXPECT_FALSE(IsInSet('\0', "a"));
+}
+
+TEST(IsInSetTest, WorksForNonNulChars) {
+ EXPECT_FALSE(IsInSet('a', "Ab"));
+ EXPECT_FALSE(IsInSet('c', ""));
+
+ EXPECT_TRUE(IsInSet('b', "bcd"));
+ EXPECT_TRUE(IsInSet('b', "ab"));
+}
+
+TEST(IsDigitTest, IsFalseForNonDigit) {
+ EXPECT_FALSE(IsDigit('\0'));
+ EXPECT_FALSE(IsDigit(' '));
+ EXPECT_FALSE(IsDigit('+'));
+ EXPECT_FALSE(IsDigit('-'));
+ EXPECT_FALSE(IsDigit('.'));
+ EXPECT_FALSE(IsDigit('a'));
+}
+
+TEST(IsDigitTest, IsTrueForDigit) {
+ EXPECT_TRUE(IsDigit('0'));
+ EXPECT_TRUE(IsDigit('1'));
+ EXPECT_TRUE(IsDigit('5'));
+ EXPECT_TRUE(IsDigit('9'));
+}
+
+TEST(IsPunctTest, IsFalseForNonPunct) {
+ EXPECT_FALSE(IsPunct('\0'));
+ EXPECT_FALSE(IsPunct(' '));
+ EXPECT_FALSE(IsPunct('\n'));
+ EXPECT_FALSE(IsPunct('a'));
+ EXPECT_FALSE(IsPunct('0'));
+}
+
+TEST(IsPunctTest, IsTrueForPunct) {
+ for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) {
+ EXPECT_PRED1(IsPunct, *p);
+ }
+}
+
+TEST(IsRepeatTest, IsFalseForNonRepeatChar) {
+ EXPECT_FALSE(IsRepeat('\0'));
+ EXPECT_FALSE(IsRepeat(' '));
+ EXPECT_FALSE(IsRepeat('a'));
+ EXPECT_FALSE(IsRepeat('1'));
+ EXPECT_FALSE(IsRepeat('-'));
+}
+
+TEST(IsRepeatTest, IsTrueForRepeatChar) {
+ EXPECT_TRUE(IsRepeat('?'));
+ EXPECT_TRUE(IsRepeat('*'));
+ EXPECT_TRUE(IsRepeat('+'));
+}
+
+TEST(IsWhiteSpaceTest, IsFalseForNonWhiteSpace) {
+ EXPECT_FALSE(IsWhiteSpace('\0'));
+ EXPECT_FALSE(IsWhiteSpace('a'));
+ EXPECT_FALSE(IsWhiteSpace('1'));
+ EXPECT_FALSE(IsWhiteSpace('+'));
+ EXPECT_FALSE(IsWhiteSpace('_'));
+}
+
+TEST(IsWhiteSpaceTest, IsTrueForWhiteSpace) {
+ EXPECT_TRUE(IsWhiteSpace(' '));
+ EXPECT_TRUE(IsWhiteSpace('\n'));
+ EXPECT_TRUE(IsWhiteSpace('\r'));
+ EXPECT_TRUE(IsWhiteSpace('\t'));
+ EXPECT_TRUE(IsWhiteSpace('\v'));
+ EXPECT_TRUE(IsWhiteSpace('\f'));
+}
+
+TEST(IsWordCharTest, IsFalseForNonWordChar) {
+ EXPECT_FALSE(IsWordChar('\0'));
+ EXPECT_FALSE(IsWordChar('+'));
+ EXPECT_FALSE(IsWordChar('.'));
+ EXPECT_FALSE(IsWordChar(' '));
+ EXPECT_FALSE(IsWordChar('\n'));
+}
+
+TEST(IsWordCharTest, IsTrueForLetter) {
+ EXPECT_TRUE(IsWordChar('a'));
+ EXPECT_TRUE(IsWordChar('b'));
+ EXPECT_TRUE(IsWordChar('A'));
+ EXPECT_TRUE(IsWordChar('Z'));
+}
+
+TEST(IsWordCharTest, IsTrueForDigit) {
+ EXPECT_TRUE(IsWordChar('0'));
+ EXPECT_TRUE(IsWordChar('1'));
+ EXPECT_TRUE(IsWordChar('7'));
+ EXPECT_TRUE(IsWordChar('9'));
+}
+
+TEST(IsWordCharTest, IsTrueForUnderscore) {
+ EXPECT_TRUE(IsWordChar('_'));
+}
+
+TEST(IsValidEscapeTest, IsFalseForNonPrintable) {
+ EXPECT_FALSE(IsValidEscape('\0'));
+ EXPECT_FALSE(IsValidEscape('\007'));
+}
+
+TEST(IsValidEscapeTest, IsFalseForDigit) {
+ EXPECT_FALSE(IsValidEscape('0'));
+ EXPECT_FALSE(IsValidEscape('9'));
+}
+
+TEST(IsValidEscapeTest, IsFalseForWhiteSpace) {
+ EXPECT_FALSE(IsValidEscape(' '));
+ EXPECT_FALSE(IsValidEscape('\n'));
+}
+
+TEST(IsValidEscapeTest, IsFalseForSomeLetter) {
+ EXPECT_FALSE(IsValidEscape('a'));
+ EXPECT_FALSE(IsValidEscape('Z'));
+}
+
+TEST(IsValidEscapeTest, IsTrueForPunct) {
+ EXPECT_TRUE(IsValidEscape('.'));
+ EXPECT_TRUE(IsValidEscape('-'));
+ EXPECT_TRUE(IsValidEscape('^'));
+ EXPECT_TRUE(IsValidEscape('$'));
+ EXPECT_TRUE(IsValidEscape('('));
+ EXPECT_TRUE(IsValidEscape(']'));
+ EXPECT_TRUE(IsValidEscape('{'));
+ EXPECT_TRUE(IsValidEscape('|'));
+}
+
+TEST(IsValidEscapeTest, IsTrueForSomeLetter) {
+ EXPECT_TRUE(IsValidEscape('d'));
+ EXPECT_TRUE(IsValidEscape('D'));
+ EXPECT_TRUE(IsValidEscape('s'));
+ EXPECT_TRUE(IsValidEscape('S'));
+ EXPECT_TRUE(IsValidEscape('w'));
+ EXPECT_TRUE(IsValidEscape('W'));
+}
+
+TEST(AtomMatchesCharTest, EscapedPunct) {
+ EXPECT_FALSE(AtomMatchesChar(true, '\\', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, '\\', ' '));
+ EXPECT_FALSE(AtomMatchesChar(true, '_', '.'));
+ EXPECT_FALSE(AtomMatchesChar(true, '.', 'a'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, '\\', '\\'));
+ EXPECT_TRUE(AtomMatchesChar(true, '_', '_'));
+ EXPECT_TRUE(AtomMatchesChar(true, '+', '+'));
+ EXPECT_TRUE(AtomMatchesChar(true, '.', '.'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_d) {
+ EXPECT_FALSE(AtomMatchesChar(true, 'd', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'd', 'a'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'd', '.'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'd', '0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'd', '9'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_D) {
+ EXPECT_FALSE(AtomMatchesChar(true, 'D', '0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'D', '9'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'D', '\0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'D', 'a'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'D', '-'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_s) {
+ EXPECT_FALSE(AtomMatchesChar(true, 's', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 's', 'a'));
+ EXPECT_FALSE(AtomMatchesChar(true, 's', '.'));
+ EXPECT_FALSE(AtomMatchesChar(true, 's', '9'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 's', ' '));
+ EXPECT_TRUE(AtomMatchesChar(true, 's', '\n'));
+ EXPECT_TRUE(AtomMatchesChar(true, 's', '\t'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_S) {
+ EXPECT_FALSE(AtomMatchesChar(true, 'S', ' '));
+ EXPECT_FALSE(AtomMatchesChar(true, 'S', '\r'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'S', '\0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'S', 'a'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'S', '9'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_w) {
+ EXPECT_FALSE(AtomMatchesChar(true, 'w', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'w', '+'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'w', ' '));
+ EXPECT_FALSE(AtomMatchesChar(true, 'w', '\n'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'w', '0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'w', 'b'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'w', 'C'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'w', '_'));
+}
+
+TEST(AtomMatchesCharTest, Escaped_W) {
+ EXPECT_FALSE(AtomMatchesChar(true, 'W', 'A'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'W', 'b'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'W', '9'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'W', '_'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'W', '\0'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'W', '*'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'W', '\n'));
+}
+
+TEST(AtomMatchesCharTest, EscapedWhiteSpace) {
+ EXPECT_FALSE(AtomMatchesChar(true, 'f', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'f', '\n'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'n', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'n', '\r'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'r', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'r', 'a'));
+ EXPECT_FALSE(AtomMatchesChar(true, 't', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 't', 't'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'v', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(true, 'v', '\f'));
+
+ EXPECT_TRUE(AtomMatchesChar(true, 'f', '\f'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'n', '\n'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'r', '\r'));
+ EXPECT_TRUE(AtomMatchesChar(true, 't', '\t'));
+ EXPECT_TRUE(AtomMatchesChar(true, 'v', '\v'));
+}
+
+TEST(AtomMatchesCharTest, UnescapedDot) {
+ EXPECT_FALSE(AtomMatchesChar(false, '.', '\n'));
+
+ EXPECT_TRUE(AtomMatchesChar(false, '.', '\0'));
+ EXPECT_TRUE(AtomMatchesChar(false, '.', '.'));
+ EXPECT_TRUE(AtomMatchesChar(false, '.', 'a'));
+ EXPECT_TRUE(AtomMatchesChar(false, '.', ' '));
+}
+
+TEST(AtomMatchesCharTest, UnescapedChar) {
+ EXPECT_FALSE(AtomMatchesChar(false, 'a', '\0'));
+ EXPECT_FALSE(AtomMatchesChar(false, 'a', 'b'));
+ EXPECT_FALSE(AtomMatchesChar(false, '$', 'a'));
+
+ EXPECT_TRUE(AtomMatchesChar(false, '$', '$'));
+ EXPECT_TRUE(AtomMatchesChar(false, '5', '5'));
+ EXPECT_TRUE(AtomMatchesChar(false, 'Z', 'Z'));
+}
+
+TEST(ValidateRegexTest, GeneratesFailureAndReturnsFalseForInvalid) {
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(NULL)),
+ "NULL is not a valid simple regular expression");
+ EXPECT_NONFATAL_FAILURE(
+ ASSERT_FALSE(ValidateRegex("a\\")),
+ "Syntax error at index 1 in simple regular expression \"a\\\": ");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a\\")),
+ "'\\' cannot appear at the end");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\n\\")),
+ "'\\' cannot appear at the end");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("\\s\\hb")),
+ "invalid escape sequence \"\\h\"");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^^")),
+ "'^' can only appear at the beginning");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex(".*^b")),
+ "'^' can only appear at the beginning");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("$$")),
+ "'$' can only appear at the end");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^$a")),
+ "'$' can only appear at the end");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a(b")),
+ "'(' is unsupported");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("ab)")),
+ "')' is unsupported");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("[ab")),
+ "'[' is unsupported");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("a{2")),
+ "'{' is unsupported");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("?")),
+ "'?' can only follow a repeatable token");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("^*")),
+ "'*' can only follow a repeatable token");
+ EXPECT_NONFATAL_FAILURE(ASSERT_FALSE(ValidateRegex("5*+")),
+ "'+' can only follow a repeatable token");
+}
+
+TEST(ValidateRegexTest, ReturnsTrueForValid) {
+ EXPECT_TRUE(ValidateRegex(""));
+ EXPECT_TRUE(ValidateRegex("a"));
+ EXPECT_TRUE(ValidateRegex(".*"));
+ EXPECT_TRUE(ValidateRegex("^a_+"));
+ EXPECT_TRUE(ValidateRegex("^a\\t\\&?"));
+ EXPECT_TRUE(ValidateRegex("09*$"));
+ EXPECT_TRUE(ValidateRegex("^Z$"));
+ EXPECT_TRUE(ValidateRegex("a\\^Z\\$\\(\\)\\|\\[\\]\\{\\}"));
+}
+
+TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrOne) {
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "a", "ba"));
+ // Repeating more than once.
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "aab"));
+
+ // Repeating zero times.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ba"));
+ // Repeating once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, 'a', '?', "b", "ab"));
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '#', '?', ".", "##"));
+}
+
+TEST(MatchRepetitionAndRegexAtHeadTest, WorksForZeroOrMany) {
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '*', "a$", "baab"));
+
+ // Repeating zero times.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "bc"));
+ // Repeating once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '*', "b", "abc"));
+ // Repeating more than once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '*', "-", "ab_1-g"));
+}
+
+TEST(MatchRepetitionAndRegexAtHeadTest, WorksForOneOrMany) {
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "a$", "baab"));
+ // Repeating zero times.
+ EXPECT_FALSE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "bc"));
+
+ // Repeating once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(false, '.', '+', "b", "abc"));
+ // Repeating more than once.
+ EXPECT_TRUE(MatchRepetitionAndRegexAtHead(true, 'w', '+', "-", "ab_1-g"));
+}
+
+TEST(MatchRegexAtHeadTest, ReturnsTrueForEmptyRegex) {
+ EXPECT_TRUE(MatchRegexAtHead("", ""));
+ EXPECT_TRUE(MatchRegexAtHead("", "ab"));
+}
+
+TEST(MatchRegexAtHeadTest, WorksWhenDollarIsInRegex) {
+ EXPECT_FALSE(MatchRegexAtHead("$", "a"));
+
+ EXPECT_TRUE(MatchRegexAtHead("$", ""));
+ EXPECT_TRUE(MatchRegexAtHead("a$", "a"));
+}
+
+TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithEscapeSequence) {
+ EXPECT_FALSE(MatchRegexAtHead("\\w", "+"));
+ EXPECT_FALSE(MatchRegexAtHead("\\W", "ab"));
+
+ EXPECT_TRUE(MatchRegexAtHead("\\sa", "\nab"));
+ EXPECT_TRUE(MatchRegexAtHead("\\d", "1a"));
+}
+
+TEST(MatchRegexAtHeadTest, WorksWhenRegexStartsWithRepetition) {
+ EXPECT_FALSE(MatchRegexAtHead(".+a", "abc"));
+ EXPECT_FALSE(MatchRegexAtHead("a?b", "aab"));
+
+ EXPECT_TRUE(MatchRegexAtHead(".*a", "bc12-ab"));
+ EXPECT_TRUE(MatchRegexAtHead("a?b", "b"));
+ EXPECT_TRUE(MatchRegexAtHead("a?b", "ab"));
+}
+
+TEST(MatchRegexAtHeadTest,
+ WorksWhenRegexStartsWithRepetionOfEscapeSequence) {
+ EXPECT_FALSE(MatchRegexAtHead("\\.+a", "abc"));
+ EXPECT_FALSE(MatchRegexAtHead("\\s?b", " b"));
+
+ EXPECT_TRUE(MatchRegexAtHead("\\(*a", "((((ab"));
+ EXPECT_TRUE(MatchRegexAtHead("\\^?b", "^b"));
+ EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "b"));
+ EXPECT_TRUE(MatchRegexAtHead("\\\\?b", "\\b"));
+}
+
+TEST(MatchRegexAtHeadTest, MatchesSequentially) {
+ EXPECT_FALSE(MatchRegexAtHead("ab.*c", "acabc"));
+
+ EXPECT_TRUE(MatchRegexAtHead("ab.*c", "ab-fsc"));
+}
+
+TEST(MatchRegexAnywhereTest, ReturnsFalseWhenStringIsNull) {
+ EXPECT_FALSE(MatchRegexAnywhere("", NULL));
+}
+
+TEST(MatchRegexAnywhereTest, WorksWhenRegexStartsWithCaret) {
+ EXPECT_FALSE(MatchRegexAnywhere("^a", "ba"));
+ EXPECT_FALSE(MatchRegexAnywhere("^$", "a"));
+
+ EXPECT_TRUE(MatchRegexAnywhere("^a", "ab"));
+ EXPECT_TRUE(MatchRegexAnywhere("^", "ab"));
+ EXPECT_TRUE(MatchRegexAnywhere("^$", ""));
+}
+
+TEST(MatchRegexAnywhereTest, ReturnsFalseWhenNoMatch) {
+ EXPECT_FALSE(MatchRegexAnywhere("a", "bcde123"));
+ EXPECT_FALSE(MatchRegexAnywhere("a.+a", "--aa88888888"));
+}
+
+TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingPrefix) {
+ EXPECT_TRUE(MatchRegexAnywhere("\\w+", "ab1_ - 5"));
+ EXPECT_TRUE(MatchRegexAnywhere(".*=", "="));
+ EXPECT_TRUE(MatchRegexAnywhere("x.*ab?.*bc", "xaaabc"));
+}
+
+TEST(MatchRegexAnywhereTest, ReturnsTrueWhenMatchingNonPrefix) {
+ EXPECT_TRUE(MatchRegexAnywhere("\\w+", "$$$ ab1_ - 5"));
+ EXPECT_TRUE(MatchRegexAnywhere("\\.+=", "= ...="));
+}
+
+// Tests RE's implicit constructors.
+TEST(RETest, ImplicitConstructorWorks) {
+ const RE empty("");
+ EXPECT_STREQ("", empty.pattern());
+
+ const RE simple("hello");
+ EXPECT_STREQ("hello", simple.pattern());
+}
+
+// Tests that RE's constructors reject invalid regular expressions.
+TEST(RETest, RejectsInvalidRegex) {
+ EXPECT_NONFATAL_FAILURE({
+ const RE normal(NULL);
+ }, "NULL is not a valid simple regular expression");
+
+ EXPECT_NONFATAL_FAILURE({
+ const RE normal(".*(\\w+");
+ }, "'(' is unsupported");
+
+ EXPECT_NONFATAL_FAILURE({
+ const RE invalid("^?");
+ }, "'?' can only follow a repeatable token");
+}
+
+// Tests RE::FullMatch().
+TEST(RETest, FullMatchWorks) {
+ const RE empty("");
+ EXPECT_TRUE(RE::FullMatch("", empty));
+ EXPECT_FALSE(RE::FullMatch("a", empty));
+
+ const RE re1("a");
+ EXPECT_TRUE(RE::FullMatch("a", re1));
+
+ const RE re("a.*z");
+ EXPECT_TRUE(RE::FullMatch("az", re));
+ EXPECT_TRUE(RE::FullMatch("axyz", re));
+ EXPECT_FALSE(RE::FullMatch("baz", re));
+ EXPECT_FALSE(RE::FullMatch("azy", re));
+}
+
+// Tests RE::PartialMatch().
+TEST(RETest, PartialMatchWorks) {
+ const RE empty("");
+ EXPECT_TRUE(RE::PartialMatch("", empty));
+ EXPECT_TRUE(RE::PartialMatch("a", empty));
+
+ const RE re("a.*z");
+ EXPECT_TRUE(RE::PartialMatch("az", re));
+ EXPECT_TRUE(RE::PartialMatch("axyz", re));
+ EXPECT_TRUE(RE::PartialMatch("baz", re));
+ EXPECT_TRUE(RE::PartialMatch("azy", re));
+ EXPECT_FALSE(RE::PartialMatch("zza", re));
+}
+
+#endif // GTEST_USES_POSIX_RE
+
+#if !GTEST_OS_WINDOWS_MOBILE
+
+TEST(CaptureTest, CapturesStdout) {
+ CaptureStdout();
+ fprintf(stdout, "abc");
+ EXPECT_STREQ("abc", GetCapturedStdout().c_str());
+
+ CaptureStdout();
+ fprintf(stdout, "def%cghi", '\0');
+ EXPECT_EQ(::std::string("def\0ghi", 7), ::std::string(GetCapturedStdout()));
+}
+
+TEST(CaptureTest, CapturesStderr) {
+ CaptureStderr();
+ fprintf(stderr, "jkl");
+ EXPECT_STREQ("jkl", GetCapturedStderr().c_str());
+
+ CaptureStderr();
+ fprintf(stderr, "jkl%cmno", '\0');
+ EXPECT_EQ(::std::string("jkl\0mno", 7), ::std::string(GetCapturedStderr()));
+}
+
+// Tests that stdout and stderr capture don't interfere with each other.
+TEST(CaptureTest, CapturesStdoutAndStderr) {
+ CaptureStdout();
+ CaptureStderr();
+ fprintf(stdout, "pqr");
+ fprintf(stderr, "stu");
+ EXPECT_STREQ("pqr", GetCapturedStdout().c_str());
+ EXPECT_STREQ("stu", GetCapturedStderr().c_str());
+}
+
+TEST(CaptureDeathTest, CannotReenterStdoutCapture) {
+ CaptureStdout();
+ EXPECT_DEATH_IF_SUPPORTED(CaptureStdout();,
+ "Only one stdout capturer can exist at a time");
+ GetCapturedStdout();
+
+ // We cannot test stderr capturing using death tests as they use it
+ // themselves.
+}
+
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+TEST(ThreadLocalTest, DefaultConstructorInitializesToDefaultValues) {
+ ThreadLocal<int> t1;
+ EXPECT_EQ(0, t1.get());
+
+ ThreadLocal<void*> t2;
+ EXPECT_TRUE(t2.get() == NULL);
+}
+
+TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) {
+ ThreadLocal<int> t1(123);
+ EXPECT_EQ(123, t1.get());
+
+ int i = 0;
+ ThreadLocal<int*> t2(&i);
+ EXPECT_EQ(&i, t2.get());
+}
+
+class NoDefaultContructor {
+ public:
+ explicit NoDefaultContructor(const char*) {}
+ NoDefaultContructor(const NoDefaultContructor&) {}
+};
+
+TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) {
+ ThreadLocal<NoDefaultContructor> bar(NoDefaultContructor("foo"));
+ bar.pointer();
+}
+
+TEST(ThreadLocalTest, GetAndPointerReturnSameValue) {
+ ThreadLocal<String> thread_local;
+
+ EXPECT_EQ(thread_local.pointer(), &(thread_local.get()));
+
+ // Verifies the condition still holds after calling set.
+ thread_local.set("foo");
+ EXPECT_EQ(thread_local.pointer(), &(thread_local.get()));
+}
+
+TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) {
+ ThreadLocal<String> thread_local;
+ const ThreadLocal<String>& const_thread_local = thread_local;
+
+ EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer());
+
+ thread_local.set("foo");
+ EXPECT_EQ(thread_local.pointer(), const_thread_local.pointer());
+}
+
+#if GTEST_IS_THREADSAFE
+
+void AddTwo(int* param) { *param += 2; }
+
+TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) {
+ int i = 40;
+ ThreadWithParam<int*> thread(&AddTwo, &i, NULL);
+ thread.Join();
+ EXPECT_EQ(42, i);
+}
+
+TEST(MutexDeathTest, AssertHeldShouldAssertWhenNotLocked) {
+ // AssertHeld() is flaky only in the presence of multiple threads accessing
+ // the lock. In this case, the test is robust.
+ EXPECT_DEATH_IF_SUPPORTED({
+ Mutex m;
+ { MutexLock lock(&m); }
+ m.AssertHeld();
+ },
+ "thread .*hold");
+}
+
+TEST(MutexTest, AssertHeldShouldNotAssertWhenLocked) {
+ Mutex m;
+ MutexLock lock(&m);
+ m.AssertHeld();
+}
+
+class AtomicCounterWithMutex {
+ public:
+ explicit AtomicCounterWithMutex(Mutex* mutex) :
+ value_(0), mutex_(mutex), random_(42) {}
+
+ void Increment() {
+ MutexLock lock(mutex_);
+ int temp = value_;
+ {
+ // Locking a mutex puts up a memory barrier, preventing reads and
+ // writes to value_ rearranged when observed from other threads.
+ //
+ // We cannot use Mutex and MutexLock here or rely on their memory
+ // barrier functionality as we are testing them here.
+ pthread_mutex_t memory_barrier_mutex;
+ GTEST_CHECK_POSIX_SUCCESS_(
+ pthread_mutex_init(&memory_barrier_mutex, NULL));
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&memory_barrier_mutex));
+
+ SleepMilliseconds(random_.Generate(30));
+
+ GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&memory_barrier_mutex));
+ }
+ value_ = temp + 1;
+ }
+ int value() const { return value_; }
+
+ private:
+ volatile int value_;
+ Mutex* const mutex_; // Protects value_.
+ Random random_;
+};
+
+void CountingThreadFunc(pair<AtomicCounterWithMutex*, int> param) {
+ for (int i = 0; i < param.second; ++i)
+ param.first->Increment();
+}
+
+// Tests that the mutex only lets one thread at a time to lock it.
+TEST(MutexTest, OnlyOneThreadCanLockAtATime) {
+ Mutex mutex;
+ AtomicCounterWithMutex locked_counter(&mutex);
+
+ typedef ThreadWithParam<pair<AtomicCounterWithMutex*, int> > ThreadType;
+ const int kCycleCount = 20;
+ const int kThreadCount = 7;
+ scoped_ptr<ThreadType> counting_threads[kThreadCount];
+ Notification threads_can_start;
+ // Creates and runs kThreadCount threads that increment locked_counter
+ // kCycleCount times each.
+ for (int i = 0; i < kThreadCount; ++i) {
+ counting_threads[i].reset(new ThreadType(&CountingThreadFunc,
+ make_pair(&locked_counter,
+ kCycleCount),
+ &threads_can_start));
+ }
+ threads_can_start.Notify();
+ for (int i = 0; i < kThreadCount; ++i)
+ counting_threads[i]->Join();
+
+ // If the mutex lets more than one thread to increment the counter at a
+ // time, they are likely to encounter a race condition and have some
+ // increments overwritten, resulting in the lower then expected counter
+ // value.
+ EXPECT_EQ(kCycleCount * kThreadCount, locked_counter.value());
+}
+
+template <typename T>
+void RunFromThread(void (func)(T), T param) {
+ ThreadWithParam<T> thread(func, param, NULL);
+ thread.Join();
+}
+
+void RetrieveThreadLocalValue(pair<ThreadLocal<String>*, String*> param) {
+ *param.second = param.first->get();
+}
+
+TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) {
+ ThreadLocal<String> thread_local("foo");
+ EXPECT_STREQ("foo", thread_local.get().c_str());
+
+ thread_local.set("bar");
+ EXPECT_STREQ("bar", thread_local.get().c_str());
+
+ String result;
+ RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result));
+ EXPECT_STREQ("foo", result.c_str());
+}
+
+// DestructorTracker keeps track of whether its instances have been
+// destroyed.
+static std::vector<bool> g_destroyed;
+
+class DestructorTracker {
+ public:
+ DestructorTracker() : index_(GetNewIndex()) {}
+ DestructorTracker(const DestructorTracker& /* rhs */)
+ : index_(GetNewIndex()) {}
+ ~DestructorTracker() {
+ // We never access g_destroyed concurrently, so we don't need to
+ // protect the write operation under a mutex.
+ g_destroyed[index_] = true;
+ }
+
+ private:
+ static int GetNewIndex() {
+ g_destroyed.push_back(false);
+ return g_destroyed.size() - 1;
+ }
+ const int index_;
+};
+
+typedef ThreadLocal<DestructorTracker>* ThreadParam;
+
+void CallThreadLocalGet(ThreadParam thread_local) {
+ thread_local->get();
+}
+
+// Tests that when a ThreadLocal object dies in a thread, it destroys
+// the managed object for that thread.
+TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) {
+ g_destroyed.clear();
+
+ {
+ // The next line default constructs a DestructorTracker object as
+ // the default value of objects managed by thread_local.
+ ThreadLocal<DestructorTracker> thread_local;
+ ASSERT_EQ(1U, g_destroyed.size());
+ ASSERT_FALSE(g_destroyed[0]);
+
+ // This creates another DestructorTracker object for the main thread.
+ thread_local.get();
+ ASSERT_EQ(2U, g_destroyed.size());
+ ASSERT_FALSE(g_destroyed[0]);
+ ASSERT_FALSE(g_destroyed[1]);
+ }
+
+ // Now thread_local has died. It should have destroyed both the
+ // default value shared by all threads and the value for the main
+ // thread.
+ ASSERT_EQ(2U, g_destroyed.size());
+ EXPECT_TRUE(g_destroyed[0]);
+ EXPECT_TRUE(g_destroyed[1]);
+
+ g_destroyed.clear();
+}
+
+// Tests that when a thread exits, the thread-local object for that
+// thread is destroyed.
+TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) {
+ g_destroyed.clear();
+
+ {
+ // The next line default constructs a DestructorTracker object as
+ // the default value of objects managed by thread_local.
+ ThreadLocal<DestructorTracker> thread_local;
+ ASSERT_EQ(1U, g_destroyed.size());
+ ASSERT_FALSE(g_destroyed[0]);
+
+ // This creates another DestructorTracker object in the new thread.
+ ThreadWithParam<ThreadParam> thread(
+ &CallThreadLocalGet, &thread_local, NULL);
+ thread.Join();
+
+ // Now the new thread has exited. The per-thread object for it
+ // should have been destroyed.
+ ASSERT_EQ(2U, g_destroyed.size());
+ ASSERT_FALSE(g_destroyed[0]);
+ ASSERT_TRUE(g_destroyed[1]);
+ }
+
+ // Now thread_local has died. The default value should have been
+ // destroyed too.
+ ASSERT_EQ(2U, g_destroyed.size());
+ EXPECT_TRUE(g_destroyed[0]);
+ EXPECT_TRUE(g_destroyed[1]);
+
+ g_destroyed.clear();
+}
+
+TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) {
+ ThreadLocal<String> thread_local;
+ thread_local.set("Foo");
+ EXPECT_STREQ("Foo", thread_local.get().c_str());
+
+ String result;
+ RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local, &result));
+ EXPECT_TRUE(result.c_str() == NULL);
+}
+
+#endif // GTEST_IS_THREADSAFE
+
+} // namespace internal
+} // namespace testing
diff --git a/Source/ThirdParty/gtest/test/gtest-test-part_test.cc b/Source/ThirdParty/gtest/test/gtest-test-part_test.cc
new file mode 100644
index 000000000..5a3e9196a
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-test-part_test.cc
@@ -0,0 +1,208 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+
+#include <gtest/gtest-test-part.h>
+
+#include <gtest/gtest.h>
+
+using testing::Message;
+using testing::Test;
+using testing::TestPartResult;
+using testing::TestPartResultArray;
+
+namespace {
+
+// Tests the TestPartResult class.
+
+// The test fixture for testing TestPartResult.
+class TestPartResultTest : public Test {
+ protected:
+ TestPartResultTest()
+ : r1_(TestPartResult::kSuccess, "foo/bar.cc", 10, "Success!"),
+ r2_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure!"),
+ r3_(TestPartResult::kFatalFailure, NULL, -1, "Failure!") {}
+
+ TestPartResult r1_, r2_, r3_;
+};
+
+
+TEST_F(TestPartResultTest, ConstructorWorks) {
+ Message message;
+ message << "something is terribly wrong";
+ message << static_cast<const char*>(testing::internal::kStackTraceMarker);
+ message << "some unimportant stack trace";
+
+ const TestPartResult result(TestPartResult::kNonFatalFailure,
+ "some_file.cc",
+ 42,
+ message.GetString().c_str());
+
+ EXPECT_EQ(TestPartResult::kNonFatalFailure, result.type());
+ EXPECT_STREQ("some_file.cc", result.file_name());
+ EXPECT_EQ(42, result.line_number());
+ EXPECT_STREQ(message.GetString().c_str(), result.message());
+ EXPECT_STREQ("something is terribly wrong", result.summary());
+}
+
+TEST_F(TestPartResultTest, ResultAccessorsWork) {
+ const TestPartResult success(TestPartResult::kSuccess,
+ "file.cc",
+ 42,
+ "message");
+ EXPECT_TRUE(success.passed());
+ EXPECT_FALSE(success.failed());
+ EXPECT_FALSE(success.nonfatally_failed());
+ EXPECT_FALSE(success.fatally_failed());
+
+ const TestPartResult nonfatal_failure(TestPartResult::kNonFatalFailure,
+ "file.cc",
+ 42,
+ "message");
+ EXPECT_FALSE(nonfatal_failure.passed());
+ EXPECT_TRUE(nonfatal_failure.failed());
+ EXPECT_TRUE(nonfatal_failure.nonfatally_failed());
+ EXPECT_FALSE(nonfatal_failure.fatally_failed());
+
+ const TestPartResult fatal_failure(TestPartResult::kFatalFailure,
+ "file.cc",
+ 42,
+ "message");
+ EXPECT_FALSE(fatal_failure.passed());
+ EXPECT_TRUE(fatal_failure.failed());
+ EXPECT_FALSE(fatal_failure.nonfatally_failed());
+ EXPECT_TRUE(fatal_failure.fatally_failed());
+}
+
+// Tests TestPartResult::type().
+TEST_F(TestPartResultTest, type) {
+ EXPECT_EQ(TestPartResult::kSuccess, r1_.type());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure, r2_.type());
+ EXPECT_EQ(TestPartResult::kFatalFailure, r3_.type());
+}
+
+// Tests TestPartResult::file_name().
+TEST_F(TestPartResultTest, file_name) {
+ EXPECT_STREQ("foo/bar.cc", r1_.file_name());
+ EXPECT_STREQ(NULL, r3_.file_name());
+}
+
+// Tests TestPartResult::line_number().
+TEST_F(TestPartResultTest, line_number) {
+ EXPECT_EQ(10, r1_.line_number());
+ EXPECT_EQ(-1, r2_.line_number());
+}
+
+// Tests TestPartResult::message().
+TEST_F(TestPartResultTest, message) {
+ EXPECT_STREQ("Success!", r1_.message());
+}
+
+// Tests TestPartResult::passed().
+TEST_F(TestPartResultTest, Passed) {
+ EXPECT_TRUE(r1_.passed());
+ EXPECT_FALSE(r2_.passed());
+ EXPECT_FALSE(r3_.passed());
+}
+
+// Tests TestPartResult::failed().
+TEST_F(TestPartResultTest, Failed) {
+ EXPECT_FALSE(r1_.failed());
+ EXPECT_TRUE(r2_.failed());
+ EXPECT_TRUE(r3_.failed());
+}
+
+// Tests TestPartResult::fatally_failed().
+TEST_F(TestPartResultTest, FatallyFailed) {
+ EXPECT_FALSE(r1_.fatally_failed());
+ EXPECT_FALSE(r2_.fatally_failed());
+ EXPECT_TRUE(r3_.fatally_failed());
+}
+
+// Tests TestPartResult::nonfatally_failed().
+TEST_F(TestPartResultTest, NonfatallyFailed) {
+ EXPECT_FALSE(r1_.nonfatally_failed());
+ EXPECT_TRUE(r2_.nonfatally_failed());
+ EXPECT_FALSE(r3_.nonfatally_failed());
+}
+
+// Tests the TestPartResultArray class.
+
+class TestPartResultArrayTest : public Test {
+ protected:
+ TestPartResultArrayTest()
+ : r1_(TestPartResult::kNonFatalFailure, "foo/bar.cc", -1, "Failure 1"),
+ r2_(TestPartResult::kFatalFailure, "foo/bar.cc", -1, "Failure 2") {}
+
+ const TestPartResult r1_, r2_;
+};
+
+// Tests that TestPartResultArray initially has size 0.
+TEST_F(TestPartResultArrayTest, InitialSizeIsZero) {
+ TestPartResultArray results;
+ EXPECT_EQ(0, results.size());
+}
+
+// Tests that TestPartResultArray contains the given TestPartResult
+// after one Append() operation.
+TEST_F(TestPartResultArrayTest, ContainsGivenResultAfterAppend) {
+ TestPartResultArray results;
+ results.Append(r1_);
+ EXPECT_EQ(1, results.size());
+ EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message());
+}
+
+// Tests that TestPartResultArray contains the given TestPartResults
+// after two Append() operations.
+TEST_F(TestPartResultArrayTest, ContainsGivenResultsAfterTwoAppends) {
+ TestPartResultArray results;
+ results.Append(r1_);
+ results.Append(r2_);
+ EXPECT_EQ(2, results.size());
+ EXPECT_STREQ("Failure 1", results.GetTestPartResult(0).message());
+ EXPECT_STREQ("Failure 2", results.GetTestPartResult(1).message());
+}
+
+typedef TestPartResultArrayTest TestPartResultArrayDeathTest;
+
+// Tests that the program dies when GetTestPartResult() is called with
+// an invalid index.
+TEST_F(TestPartResultArrayDeathTest, DiesWhenIndexIsOutOfBound) {
+ TestPartResultArray results;
+ results.Append(r1_);
+
+ EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(-1), "");
+ EXPECT_DEATH_IF_SUPPORTED(results.GetTestPartResult(1), "");
+}
+
+// TODO(mheule@google.com): Add a test for the class HasNewFatalFailureHelper.
+
+} // namespace
diff --git a/Source/ThirdParty/gtest/test/gtest-tuple_test.cc b/Source/ThirdParty/gtest/test/gtest-tuple_test.cc
new file mode 100644
index 000000000..532f70b3d
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-tuple_test.cc
@@ -0,0 +1,320 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/internal/gtest-tuple.h>
+#include <utility>
+#include <gtest/gtest.h>
+
+namespace {
+
+using ::std::tr1::get;
+using ::std::tr1::make_tuple;
+using ::std::tr1::tuple;
+using ::std::tr1::tuple_element;
+using ::std::tr1::tuple_size;
+using ::testing::StaticAssertTypeEq;
+
+// Tests that tuple_element<K, tuple<T0, T1, ..., TN> >::type returns TK.
+TEST(tuple_element_Test, ReturnsElementType) {
+ StaticAssertTypeEq<int, tuple_element<0, tuple<int, char> >::type>();
+ StaticAssertTypeEq<int&, tuple_element<1, tuple<double, int&> >::type>();
+ StaticAssertTypeEq<bool, tuple_element<2, tuple<double, int, bool> >::type>();
+}
+
+// Tests that tuple_size<T>::value gives the number of fields in tuple
+// type T.
+TEST(tuple_size_Test, ReturnsNumberOfFields) {
+ EXPECT_EQ(0, +tuple_size<tuple<> >::value);
+ EXPECT_EQ(1, +tuple_size<tuple<void*> >::value);
+ EXPECT_EQ(1, +tuple_size<tuple<char> >::value);
+ EXPECT_EQ(1, +(tuple_size<tuple<tuple<int, double> > >::value));
+ EXPECT_EQ(2, +(tuple_size<tuple<int&, const char> >::value));
+ EXPECT_EQ(3, +(tuple_size<tuple<char*, void, const bool&> >::value));
+}
+
+// Tests comparing a tuple with itself.
+TEST(ComparisonTest, ComparesWithSelf) {
+ const tuple<int, char, bool> a(5, 'a', false);
+
+ EXPECT_TRUE(a == a);
+ EXPECT_FALSE(a != a);
+}
+
+// Tests comparing two tuples with the same value.
+TEST(ComparisonTest, ComparesEqualTuples) {
+ const tuple<int, bool> a(5, true), b(5, true);
+
+ EXPECT_TRUE(a == b);
+ EXPECT_FALSE(a != b);
+}
+
+// Tests comparing two different tuples that have no reference fields.
+TEST(ComparisonTest, ComparesUnequalTuplesWithoutReferenceFields) {
+ typedef tuple<const int, char> FooTuple;
+
+ const FooTuple a(0, 'x');
+ const FooTuple b(1, 'a');
+
+ EXPECT_TRUE(a != b);
+ EXPECT_FALSE(a == b);
+
+ const FooTuple c(1, 'b');
+
+ EXPECT_TRUE(b != c);
+ EXPECT_FALSE(b == c);
+}
+
+// Tests comparing two different tuples that have reference fields.
+TEST(ComparisonTest, ComparesUnequalTuplesWithReferenceFields) {
+ typedef tuple<int&, const char&> FooTuple;
+
+ int i = 5;
+ const char ch = 'a';
+ const FooTuple a(i, ch);
+
+ int j = 6;
+ const FooTuple b(j, ch);
+
+ EXPECT_TRUE(a != b);
+ EXPECT_FALSE(a == b);
+
+ j = 5;
+ const char ch2 = 'b';
+ const FooTuple c(j, ch2);
+
+ EXPECT_TRUE(b != c);
+ EXPECT_FALSE(b == c);
+}
+
+// Tests that a tuple field with a reference type is an alias of the
+// variable it's supposed to reference.
+TEST(ReferenceFieldTest, IsAliasOfReferencedVariable) {
+ int n = 0;
+ tuple<bool, int&> t(true, n);
+
+ n = 1;
+ EXPECT_EQ(n, get<1>(t))
+ << "Changing a underlying variable should update the reference field.";
+
+ // Makes sure that the implementation doesn't do anything funny with
+ // the & operator for the return type of get<>().
+ EXPECT_EQ(&n, &(get<1>(t)))
+ << "The address of a reference field should equal the address of "
+ << "the underlying variable.";
+
+ get<1>(t) = 2;
+ EXPECT_EQ(2, n)
+ << "Changing a reference field should update the underlying variable.";
+}
+
+// Tests that tuple's default constructor default initializes each field.
+// This test needs to compile without generating warnings.
+TEST(TupleConstructorTest, DefaultConstructorDefaultInitializesEachField) {
+ // The TR1 report requires that tuple's default constructor default
+ // initializes each field, even if it's a primitive type. If the
+ // implementation forgets to do this, this test will catch it by
+ // generating warnings about using uninitialized variables (assuming
+ // a decent compiler).
+
+ tuple<> empty;
+
+ tuple<int> a1, b1;
+ b1 = a1;
+ EXPECT_EQ(0, get<0>(b1));
+
+ tuple<int, double> a2, b2;
+ b2 = a2;
+ EXPECT_EQ(0, get<0>(b2));
+ EXPECT_EQ(0.0, get<1>(b2));
+
+ tuple<double, char, bool*> a3, b3;
+ b3 = a3;
+ EXPECT_EQ(0.0, get<0>(b3));
+ EXPECT_EQ('\0', get<1>(b3));
+ EXPECT_TRUE(get<2>(b3) == NULL);
+
+ tuple<int, int, int, int, int, int, int, int, int, int> a10, b10;
+ b10 = a10;
+ EXPECT_EQ(0, get<0>(b10));
+ EXPECT_EQ(0, get<1>(b10));
+ EXPECT_EQ(0, get<2>(b10));
+ EXPECT_EQ(0, get<3>(b10));
+ EXPECT_EQ(0, get<4>(b10));
+ EXPECT_EQ(0, get<5>(b10));
+ EXPECT_EQ(0, get<6>(b10));
+ EXPECT_EQ(0, get<7>(b10));
+ EXPECT_EQ(0, get<8>(b10));
+ EXPECT_EQ(0, get<9>(b10));
+}
+
+// Tests constructing a tuple from its fields.
+TEST(TupleConstructorTest, ConstructsFromFields) {
+ int n = 1;
+ // Reference field.
+ tuple<int&> a(n);
+ EXPECT_EQ(&n, &(get<0>(a)));
+
+ // Non-reference fields.
+ tuple<int, char> b(5, 'a');
+ EXPECT_EQ(5, get<0>(b));
+ EXPECT_EQ('a', get<1>(b));
+
+ // Const reference field.
+ const int m = 2;
+ tuple<bool, const int&> c(true, m);
+ EXPECT_TRUE(get<0>(c));
+ EXPECT_EQ(&m, &(get<1>(c)));
+}
+
+// Tests tuple's copy constructor.
+TEST(TupleConstructorTest, CopyConstructor) {
+ tuple<double, bool> a(0.0, true);
+ tuple<double, bool> b(a);
+
+ EXPECT_DOUBLE_EQ(0.0, get<0>(b));
+ EXPECT_TRUE(get<1>(b));
+}
+
+// Tests constructing a tuple from another tuple that has a compatible
+// but different type.
+TEST(TupleConstructorTest, ConstructsFromDifferentTupleType) {
+ tuple<int, int, char> a(0, 1, 'a');
+ tuple<double, long, int> b(a);
+
+ EXPECT_DOUBLE_EQ(0.0, get<0>(b));
+ EXPECT_EQ(1, get<1>(b));
+ EXPECT_EQ('a', get<2>(b));
+}
+
+// Tests constructing a 2-tuple from an std::pair.
+TEST(TupleConstructorTest, ConstructsFromPair) {
+ ::std::pair<int, char> a(1, 'a');
+ tuple<int, char> b(a);
+ tuple<int, const char&> c(a);
+}
+
+// Tests assigning a tuple to another tuple with the same type.
+TEST(TupleAssignmentTest, AssignsToSameTupleType) {
+ const tuple<int, long> a(5, 7L);
+ tuple<int, long> b;
+ b = a;
+ EXPECT_EQ(5, get<0>(b));
+ EXPECT_EQ(7L, get<1>(b));
+}
+
+// Tests assigning a tuple to another tuple with a different but
+// compatible type.
+TEST(TupleAssignmentTest, AssignsToDifferentTupleType) {
+ const tuple<int, long, bool> a(1, 7L, true);
+ tuple<long, int, bool> b;
+ b = a;
+ EXPECT_EQ(1L, get<0>(b));
+ EXPECT_EQ(7, get<1>(b));
+ EXPECT_TRUE(get<2>(b));
+}
+
+// Tests assigning an std::pair to a 2-tuple.
+TEST(TupleAssignmentTest, AssignsFromPair) {
+ const ::std::pair<int, bool> a(5, true);
+ tuple<int, bool> b;
+ b = a;
+ EXPECT_EQ(5, get<0>(b));
+ EXPECT_TRUE(get<1>(b));
+
+ tuple<long, bool> c;
+ c = a;
+ EXPECT_EQ(5L, get<0>(c));
+ EXPECT_TRUE(get<1>(c));
+}
+
+// A fixture for testing big tuples.
+class BigTupleTest : public testing::Test {
+ protected:
+ typedef tuple<int, int, int, int, int, int, int, int, int, int> BigTuple;
+
+ BigTupleTest() :
+ a_(1, 0, 0, 0, 0, 0, 0, 0, 0, 2),
+ b_(1, 0, 0, 0, 0, 0, 0, 0, 0, 3) {}
+
+ BigTuple a_, b_;
+};
+
+// Tests constructing big tuples.
+TEST_F(BigTupleTest, Construction) {
+ BigTuple a;
+ BigTuple b(b_);
+}
+
+// Tests that get<N>(t) returns the N-th (0-based) field of tuple t.
+TEST_F(BigTupleTest, get) {
+ EXPECT_EQ(1, get<0>(a_));
+ EXPECT_EQ(2, get<9>(a_));
+
+ // Tests that get() works on a const tuple too.
+ const BigTuple a(a_);
+ EXPECT_EQ(1, get<0>(a));
+ EXPECT_EQ(2, get<9>(a));
+}
+
+// Tests comparing big tuples.
+TEST_F(BigTupleTest, Comparisons) {
+ EXPECT_TRUE(a_ == a_);
+ EXPECT_FALSE(a_ != a_);
+
+ EXPECT_TRUE(a_ != b_);
+ EXPECT_FALSE(a_ == b_);
+}
+
+TEST(MakeTupleTest, WorksForScalarTypes) {
+ tuple<bool, int> a;
+ a = make_tuple(true, 5);
+ EXPECT_TRUE(get<0>(a));
+ EXPECT_EQ(5, get<1>(a));
+
+ tuple<char, int, long> b;
+ b = make_tuple('a', 'b', 5);
+ EXPECT_EQ('a', get<0>(b));
+ EXPECT_EQ('b', get<1>(b));
+ EXPECT_EQ(5, get<2>(b));
+}
+
+TEST(MakeTupleTest, WorksForPointers) {
+ int a[] = { 1, 2, 3, 4 };
+ const char* const str = "hi";
+ int* const p = a;
+
+ tuple<const char*, int*> t;
+ t = make_tuple(str, p);
+ EXPECT_EQ(str, get<0>(t));
+ EXPECT_EQ(p, get<1>(t));
+}
+
+} // namespace
diff --git a/Source/ThirdParty/gtest/test/gtest-typed-test2_test.cc b/Source/ThirdParty/gtest/test/gtest-typed-test2_test.cc
new file mode 100644
index 000000000..79a8a87dc
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-typed-test2_test.cc
@@ -0,0 +1,45 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <vector>
+
+#include "test/gtest-typed-test_test.h"
+#include <gtest/gtest.h>
+
+#if GTEST_HAS_TYPED_TEST_P
+
+// Tests that the same type-parameterized test case can be
+// instantiated in different translation units linked together.
+// (ContainerTest is also instantiated in gtest-typed-test_test.cc.)
+INSTANTIATE_TYPED_TEST_CASE_P(Vector, ContainerTest,
+ testing::Types<std::vector<int> >);
+
+#endif // GTEST_HAS_TYPED_TEST_P
diff --git a/Source/ThirdParty/gtest/test/gtest-typed-test_test.cc b/Source/ThirdParty/gtest/test/gtest-typed-test_test.cc
new file mode 100644
index 000000000..f2c397231
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-typed-test_test.cc
@@ -0,0 +1,360 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <set>
+#include <vector>
+
+#include "test/gtest-typed-test_test.h"
+#include <gtest/gtest.h>
+
+using testing::Test;
+
+// Used for testing that SetUpTestCase()/TearDownTestCase(), fixture
+// ctor/dtor, and SetUp()/TearDown() work correctly in typed tests and
+// type-parameterized test.
+template <typename T>
+class CommonTest : public Test {
+ // For some technical reason, SetUpTestCase() and TearDownTestCase()
+ // must be public.
+ public:
+ static void SetUpTestCase() {
+ shared_ = new T(5);
+ }
+
+ static void TearDownTestCase() {
+ delete shared_;
+ shared_ = NULL;
+ }
+
+ // This 'protected:' is optional. There's no harm in making all
+ // members of this fixture class template public.
+ protected:
+ // We used to use std::list here, but switched to std::vector since
+ // MSVC's <list> doesn't compile cleanly with /W4.
+ typedef std::vector<T> Vector;
+ typedef std::set<int> IntSet;
+
+ CommonTest() : value_(1) {}
+
+ virtual ~CommonTest() { EXPECT_EQ(3, value_); }
+
+ virtual void SetUp() {
+ EXPECT_EQ(1, value_);
+ value_++;
+ }
+
+ virtual void TearDown() {
+ EXPECT_EQ(2, value_);
+ value_++;
+ }
+
+ T value_;
+ static T* shared_;
+};
+
+template <typename T>
+T* CommonTest<T>::shared_ = NULL;
+
+// This #ifdef block tests typed tests.
+#if GTEST_HAS_TYPED_TEST
+
+using testing::Types;
+
+// Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor,
+// and SetUp()/TearDown() work correctly in typed tests
+
+typedef Types<char, int> TwoTypes;
+TYPED_TEST_CASE(CommonTest, TwoTypes);
+
+TYPED_TEST(CommonTest, ValuesAreCorrect) {
+ // Static members of the fixture class template can be visited via
+ // the TestFixture:: prefix.
+ EXPECT_EQ(5, *TestFixture::shared_);
+
+ // Typedefs in the fixture class template can be visited via the
+ // "typename TestFixture::" prefix.
+ typename TestFixture::Vector empty;
+ EXPECT_EQ(0U, empty.size());
+
+ typename TestFixture::IntSet empty2;
+ EXPECT_EQ(0U, empty2.size());
+
+ // Non-static members of the fixture class must be visited via
+ // 'this', as required by C++ for class templates.
+ EXPECT_EQ(2, this->value_);
+}
+
+// The second test makes sure shared_ is not deleted after the first
+// test.
+TYPED_TEST(CommonTest, ValuesAreStillCorrect) {
+ // Static members of the fixture class template can also be visited
+ // via 'this'.
+ ASSERT_TRUE(this->shared_ != NULL);
+ EXPECT_EQ(5, *this->shared_);
+
+ // TypeParam can be used to refer to the type parameter.
+ EXPECT_EQ(static_cast<TypeParam>(2), this->value_);
+}
+
+// Tests that multiple TYPED_TEST_CASE's can be defined in the same
+// translation unit.
+
+template <typename T>
+class TypedTest1 : public Test {
+};
+
+// Verifies that the second argument of TYPED_TEST_CASE can be a
+// single type.
+TYPED_TEST_CASE(TypedTest1, int);
+TYPED_TEST(TypedTest1, A) {}
+
+template <typename T>
+class TypedTest2 : public Test {
+};
+
+// Verifies that the second argument of TYPED_TEST_CASE can be a
+// Types<...> type list.
+TYPED_TEST_CASE(TypedTest2, Types<int>);
+
+// This also verifies that tests from different typed test cases can
+// share the same name.
+TYPED_TEST(TypedTest2, A) {}
+
+// Tests that a typed test case can be defined in a namespace.
+
+namespace library1 {
+
+template <typename T>
+class NumericTest : public Test {
+};
+
+typedef Types<int, long> NumericTypes;
+TYPED_TEST_CASE(NumericTest, NumericTypes);
+
+TYPED_TEST(NumericTest, DefaultIsZero) {
+ EXPECT_EQ(0, TypeParam());
+}
+
+} // namespace library1
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// This #ifdef block tests type-parameterized tests.
+#if GTEST_HAS_TYPED_TEST_P
+
+using testing::Types;
+using testing::internal::TypedTestCasePState;
+
+// Tests TypedTestCasePState.
+
+class TypedTestCasePStateTest : public Test {
+ protected:
+ virtual void SetUp() {
+ state_.AddTestName("foo.cc", 0, "FooTest", "A");
+ state_.AddTestName("foo.cc", 0, "FooTest", "B");
+ state_.AddTestName("foo.cc", 0, "FooTest", "C");
+ }
+
+ TypedTestCasePState state_;
+};
+
+TEST_F(TypedTestCasePStateTest, SucceedsForMatchingList) {
+ const char* tests = "A, B, C";
+ EXPECT_EQ(tests,
+ state_.VerifyRegisteredTestNames("foo.cc", 1, tests));
+}
+
+// Makes sure that the order of the tests and spaces around the names
+// don't matter.
+TEST_F(TypedTestCasePStateTest, IgnoresOrderAndSpaces) {
+ const char* tests = "A,C, B";
+ EXPECT_EQ(tests,
+ state_.VerifyRegisteredTestNames("foo.cc", 1, tests));
+}
+
+typedef TypedTestCasePStateTest TypedTestCasePStateDeathTest;
+
+TEST_F(TypedTestCasePStateDeathTest, DetectsDuplicates) {
+ EXPECT_DEATH_IF_SUPPORTED(
+ state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, A, C"),
+ "foo\\.cc.1.?: Test A is listed more than once\\.");
+}
+
+TEST_F(TypedTestCasePStateDeathTest, DetectsExtraTest) {
+ EXPECT_DEATH_IF_SUPPORTED(
+ state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C, D"),
+ "foo\\.cc.1.?: No test named D can be found in this test case\\.");
+}
+
+TEST_F(TypedTestCasePStateDeathTest, DetectsMissedTest) {
+ EXPECT_DEATH_IF_SUPPORTED(
+ state_.VerifyRegisteredTestNames("foo.cc", 1, "A, C"),
+ "foo\\.cc.1.?: You forgot to list test B\\.");
+}
+
+// Tests that defining a test for a parameterized test case generates
+// a run-time error if the test case has been registered.
+TEST_F(TypedTestCasePStateDeathTest, DetectsTestAfterRegistration) {
+ state_.VerifyRegisteredTestNames("foo.cc", 1, "A, B, C");
+ EXPECT_DEATH_IF_SUPPORTED(
+ state_.AddTestName("foo.cc", 2, "FooTest", "D"),
+ "foo\\.cc.2.?: Test D must be defined before REGISTER_TYPED_TEST_CASE_P"
+ "\\(FooTest, \\.\\.\\.\\)\\.");
+}
+
+// Tests that SetUpTestCase()/TearDownTestCase(), fixture ctor/dtor,
+// and SetUp()/TearDown() work correctly in type-parameterized tests.
+
+template <typename T>
+class DerivedTest : public CommonTest<T> {
+};
+
+TYPED_TEST_CASE_P(DerivedTest);
+
+TYPED_TEST_P(DerivedTest, ValuesAreCorrect) {
+ // Static members of the fixture class template can be visited via
+ // the TestFixture:: prefix.
+ EXPECT_EQ(5, *TestFixture::shared_);
+
+ // Non-static members of the fixture class must be visited via
+ // 'this', as required by C++ for class templates.
+ EXPECT_EQ(2, this->value_);
+}
+
+// The second test makes sure shared_ is not deleted after the first
+// test.
+TYPED_TEST_P(DerivedTest, ValuesAreStillCorrect) {
+ // Static members of the fixture class template can also be visited
+ // via 'this'.
+ ASSERT_TRUE(this->shared_ != NULL);
+ EXPECT_EQ(5, *this->shared_);
+ EXPECT_EQ(2, this->value_);
+}
+
+REGISTER_TYPED_TEST_CASE_P(DerivedTest,
+ ValuesAreCorrect, ValuesAreStillCorrect);
+
+typedef Types<short, long> MyTwoTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, DerivedTest, MyTwoTypes);
+
+// Tests that multiple TYPED_TEST_CASE_P's can be defined in the same
+// translation unit.
+
+template <typename T>
+class TypedTestP1 : public Test {
+};
+
+TYPED_TEST_CASE_P(TypedTestP1);
+
+// For testing that the code between TYPED_TEST_CASE_P() and
+// TYPED_TEST_P() is not enclosed in a namespace.
+typedef int IntAfterTypedTestCaseP;
+
+TYPED_TEST_P(TypedTestP1, A) {}
+TYPED_TEST_P(TypedTestP1, B) {}
+
+// For testing that the code between TYPED_TEST_P() and
+// REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace.
+typedef int IntBeforeRegisterTypedTestCaseP;
+
+REGISTER_TYPED_TEST_CASE_P(TypedTestP1, A, B);
+
+template <typename T>
+class TypedTestP2 : public Test {
+};
+
+TYPED_TEST_CASE_P(TypedTestP2);
+
+// This also verifies that tests from different type-parameterized
+// test cases can share the same name.
+TYPED_TEST_P(TypedTestP2, A) {}
+
+REGISTER_TYPED_TEST_CASE_P(TypedTestP2, A);
+
+// Verifies that the code between TYPED_TEST_CASE_P() and
+// REGISTER_TYPED_TEST_CASE_P() is not enclosed in a namespace.
+IntAfterTypedTestCaseP after = 0;
+IntBeforeRegisterTypedTestCaseP before = 0;
+
+// Verifies that the last argument of INSTANTIATE_TYPED_TEST_CASE_P()
+// can be either a single type or a Types<...> type list.
+INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP1, int);
+INSTANTIATE_TYPED_TEST_CASE_P(Int, TypedTestP2, Types<int>);
+
+// Tests that the same type-parameterized test case can be
+// instantiated more than once in the same translation unit.
+INSTANTIATE_TYPED_TEST_CASE_P(Double, TypedTestP2, Types<double>);
+
+// Tests that the same type-parameterized test case can be
+// instantiated in different translation units linked together.
+// (ContainerTest is also instantiated in gtest-typed-test_test.cc.)
+typedef Types<std::vector<double>, std::set<char> > MyContainers;
+INSTANTIATE_TYPED_TEST_CASE_P(My, ContainerTest, MyContainers);
+
+// Tests that a type-parameterized test case can be defined and
+// instantiated in a namespace.
+
+namespace library2 {
+
+template <typename T>
+class NumericTest : public Test {
+};
+
+TYPED_TEST_CASE_P(NumericTest);
+
+TYPED_TEST_P(NumericTest, DefaultIsZero) {
+ EXPECT_EQ(0, TypeParam());
+}
+
+TYPED_TEST_P(NumericTest, ZeroIsLessThanOne) {
+ EXPECT_LT(TypeParam(0), TypeParam(1));
+}
+
+REGISTER_TYPED_TEST_CASE_P(NumericTest,
+ DefaultIsZero, ZeroIsLessThanOne);
+typedef Types<int, double> NumericTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes);
+
+} // namespace library2
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P)
+
+// Google Test may not support type-parameterized tests with some
+// compilers. If we use conditional compilation to compile out all
+// code referring to the gtest_main library, MSVC linker will not link
+// that library at all and consequently complain about missing entry
+// point defined in that library (fatal error LNK1561: entry point
+// must be defined). This dummy test keeps gtest_main linked in.
+TEST(DummyTest, TypedTestsAreNotSupportedOnThisPlatform) {}
+
+#endif // #if !defined(GTEST_HAS_TYPED_TEST) && !defined(GTEST_HAS_TYPED_TEST_P)
diff --git a/Source/ThirdParty/gtest/test/gtest-typed-test_test.h b/Source/ThirdParty/gtest/test/gtest-typed-test_test.h
new file mode 100644
index 000000000..40dfeac6e
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-typed-test_test.h
@@ -0,0 +1,66 @@
+// Copyright 2008 Google Inc.
+// All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#ifndef GTEST_TEST_GTEST_TYPED_TEST_TEST_H_
+#define GTEST_TEST_GTEST_TYPED_TEST_TEST_H_
+
+#include <gtest/gtest.h>
+
+#if GTEST_HAS_TYPED_TEST_P
+
+using testing::Test;
+
+// For testing that the same type-parameterized test case can be
+// instantiated in different translation units linked together.
+// ContainerTest will be instantiated in both gtest-typed-test_test.cc
+// and gtest-typed-test2_test.cc.
+
+template <typename T>
+class ContainerTest : public Test {
+};
+
+TYPED_TEST_CASE_P(ContainerTest);
+
+TYPED_TEST_P(ContainerTest, CanBeDefaultConstructed) {
+ TypeParam container;
+}
+
+TYPED_TEST_P(ContainerTest, InitialSizeIsZero) {
+ TypeParam container;
+ EXPECT_EQ(0U, container.size());
+}
+
+REGISTER_TYPED_TEST_CASE_P(ContainerTest,
+ CanBeDefaultConstructed, InitialSizeIsZero);
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_TEST_GTEST_TYPED_TEST_TEST_H_
diff --git a/Source/ThirdParty/gtest/test/gtest-unittest-api_test.cc b/Source/ThirdParty/gtest/test/gtest-unittest-api_test.cc
new file mode 100644
index 000000000..7e0f8f804
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest-unittest-api_test.cc
@@ -0,0 +1,343 @@
+// Copyright 2009 Google Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This file contains tests verifying correctness of data provided via
+// UnitTest's public methods.
+
+#include <gtest/gtest.h>
+
+#include <string.h> // For strcmp.
+#include <algorithm>
+
+using ::testing::InitGoogleTest;
+
+namespace testing {
+namespace internal {
+
+template <typename T>
+struct LessByName {
+ bool operator()(const T* a, const T* b) {
+ return strcmp(a->name(), b->name()) < 0;
+ }
+};
+
+class UnitTestHelper {
+ public:
+ // Returns the array of pointers to all test cases sorted by the test case
+ // name. The caller is responsible for deleting the array.
+ static TestCase const** const GetSortedTestCases() {
+ UnitTest& unit_test = *UnitTest::GetInstance();
+ TestCase const** const test_cases =
+ new const TestCase*[unit_test.total_test_case_count()];
+
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i)
+ test_cases[i] = unit_test.GetTestCase(i);
+
+ std::sort(test_cases,
+ test_cases + unit_test.total_test_case_count(),
+ LessByName<TestCase>());
+ return test_cases;
+ }
+
+ // Returns the test case by its name. The caller doesn't own the returned
+ // pointer.
+ static const TestCase* FindTestCase(const char* name) {
+ UnitTest& unit_test = *UnitTest::GetInstance();
+ for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
+ const TestCase* test_case = unit_test.GetTestCase(i);
+ if (0 == strcmp(test_case->name(), name))
+ return test_case;
+ }
+ return NULL;
+ }
+
+ // Returns the array of pointers to all tests in a particular test case
+ // sorted by the test name. The caller is responsible for deleting the
+ // array.
+ static TestInfo const** const GetSortedTests(const TestCase* test_case) {
+ TestInfo const** const tests =
+ new const TestInfo*[test_case->total_test_count()];
+
+ for (int i = 0; i < test_case->total_test_count(); ++i)
+ tests[i] = test_case->GetTestInfo(i);
+
+ std::sort(tests, tests + test_case->total_test_count(),
+ LessByName<TestInfo>());
+ return tests;
+ }
+};
+
+#if GTEST_HAS_TYPED_TEST
+template <typename T> class TestCaseWithCommentTest : public Test {};
+TYPED_TEST_CASE(TestCaseWithCommentTest, Types<int>);
+TYPED_TEST(TestCaseWithCommentTest, Dummy) {}
+
+const int kTypedTestCases = 1;
+const int kTypedTests = 1;
+
+String GetExpectedTestCaseComment() {
+ Message comment;
+ comment << "TypeParam = " << GetTypeName<int>().c_str();
+ return comment.GetString();
+}
+#else
+const int kTypedTestCases = 0;
+const int kTypedTests = 0;
+#endif // GTEST_HAS_TYPED_TEST
+
+// We can only test the accessors that do not change value while tests run.
+// Since tests can be run in any order, the values the accessors that track
+// test execution (such as failed_test_count) can not be predicted.
+TEST(ApiTest, UnitTestImmutableAccessorsWork) {
+ UnitTest* unit_test = UnitTest::GetInstance();
+
+ ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count());
+ EXPECT_EQ(1 + kTypedTestCases, unit_test->test_case_to_run_count());
+ EXPECT_EQ(2, unit_test->disabled_test_count());
+ EXPECT_EQ(5 + kTypedTests, unit_test->total_test_count());
+ EXPECT_EQ(3 + kTypedTests, unit_test->test_to_run_count());
+
+ const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases();
+
+ EXPECT_STREQ("ApiTest", test_cases[0]->name());
+ EXPECT_STREQ("DISABLED_Test", test_cases[1]->name());
+#if GTEST_HAS_TYPED_TEST
+ EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name());
+#endif // GTEST_HAS_TYPED_TEST
+
+ delete[] test_cases;
+
+ // The following lines initiate actions to verify certain methods in
+ // FinalSuccessChecker::TearDown.
+
+ // Records a test property to verify TestResult::GetTestProperty().
+ RecordProperty("key", "value");
+}
+
+TEST(ApiTest, TestCaseImmutableAccessorsWork) {
+ const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest");
+ ASSERT_TRUE(test_case != NULL);
+
+ EXPECT_STREQ("ApiTest", test_case->name());
+ EXPECT_STREQ("", test_case->comment());
+ EXPECT_TRUE(test_case->should_run());
+ EXPECT_EQ(1, test_case->disabled_test_count());
+ EXPECT_EQ(3, test_case->test_to_run_count());
+ ASSERT_EQ(4, test_case->total_test_count());
+
+ const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case);
+
+ EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name());
+ EXPECT_STREQ("ApiTest", tests[0]->test_case_name());
+ EXPECT_STREQ("", tests[0]->comment());
+ EXPECT_STREQ("", tests[0]->test_case_comment());
+ EXPECT_FALSE(tests[0]->should_run());
+
+ EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name());
+ EXPECT_STREQ("ApiTest", tests[1]->test_case_name());
+ EXPECT_STREQ("", tests[1]->comment());
+ EXPECT_STREQ("", tests[1]->test_case_comment());
+ EXPECT_TRUE(tests[1]->should_run());
+
+ EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name());
+ EXPECT_STREQ("ApiTest", tests[2]->test_case_name());
+ EXPECT_STREQ("", tests[2]->comment());
+ EXPECT_STREQ("", tests[2]->test_case_comment());
+ EXPECT_TRUE(tests[2]->should_run());
+
+ EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name());
+ EXPECT_STREQ("ApiTest", tests[3]->test_case_name());
+ EXPECT_STREQ("", tests[3]->comment());
+ EXPECT_STREQ("", tests[3]->test_case_comment());
+ EXPECT_TRUE(tests[3]->should_run());
+
+ delete[] tests;
+ tests = NULL;
+
+#if GTEST_HAS_TYPED_TEST
+ test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0");
+ ASSERT_TRUE(test_case != NULL);
+
+ EXPECT_STREQ("TestCaseWithCommentTest/0", test_case->name());
+ EXPECT_STREQ(GetExpectedTestCaseComment().c_str(), test_case->comment());
+ EXPECT_TRUE(test_case->should_run());
+ EXPECT_EQ(0, test_case->disabled_test_count());
+ EXPECT_EQ(1, test_case->test_to_run_count());
+ ASSERT_EQ(1, test_case->total_test_count());
+
+ tests = UnitTestHelper::GetSortedTests(test_case);
+
+ EXPECT_STREQ("Dummy", tests[0]->name());
+ EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name());
+ EXPECT_STREQ("", tests[0]->comment());
+ EXPECT_STREQ(GetExpectedTestCaseComment().c_str(),
+ tests[0]->test_case_comment());
+ EXPECT_TRUE(tests[0]->should_run());
+
+ delete[] tests;
+#endif // GTEST_HAS_TYPED_TEST
+}
+
+TEST(ApiTest, TestCaseDisabledAccessorsWork) {
+ const TestCase* test_case = UnitTestHelper::FindTestCase("DISABLED_Test");
+ ASSERT_TRUE(test_case != NULL);
+
+ EXPECT_STREQ("DISABLED_Test", test_case->name());
+ EXPECT_STREQ("", test_case->comment());
+ EXPECT_FALSE(test_case->should_run());
+ EXPECT_EQ(1, test_case->disabled_test_count());
+ EXPECT_EQ(0, test_case->test_to_run_count());
+ ASSERT_EQ(1, test_case->total_test_count());
+
+ const TestInfo* const test_info = test_case->GetTestInfo(0);
+ EXPECT_STREQ("Dummy2", test_info->name());
+ EXPECT_STREQ("DISABLED_Test", test_info->test_case_name());
+ EXPECT_STREQ("", test_info->comment());
+ EXPECT_STREQ("", test_info->test_case_comment());
+ EXPECT_FALSE(test_info->should_run());
+}
+
+// These two tests are here to provide support for testing
+// test_case_to_run_count, disabled_test_count, and test_to_run_count.
+TEST(ApiTest, DISABLED_Dummy1) {}
+TEST(DISABLED_Test, Dummy2) {}
+
+class FinalSuccessChecker : public Environment {
+ protected:
+ virtual void TearDown() {
+ UnitTest* unit_test = UnitTest::GetInstance();
+
+ EXPECT_EQ(1 + kTypedTestCases, unit_test->successful_test_case_count());
+ EXPECT_EQ(3 + kTypedTests, unit_test->successful_test_count());
+ EXPECT_EQ(0, unit_test->failed_test_case_count());
+ EXPECT_EQ(0, unit_test->failed_test_count());
+ EXPECT_TRUE(unit_test->Passed());
+ EXPECT_FALSE(unit_test->Failed());
+ ASSERT_EQ(2 + kTypedTestCases, unit_test->total_test_case_count());
+
+ const TestCase** const test_cases = UnitTestHelper::GetSortedTestCases();
+
+ EXPECT_STREQ("ApiTest", test_cases[0]->name());
+ EXPECT_STREQ("", test_cases[0]->comment());
+ EXPECT_TRUE(test_cases[0]->should_run());
+ EXPECT_EQ(1, test_cases[0]->disabled_test_count());
+ ASSERT_EQ(4, test_cases[0]->total_test_count());
+ EXPECT_EQ(3, test_cases[0]->successful_test_count());
+ EXPECT_EQ(0, test_cases[0]->failed_test_count());
+ EXPECT_TRUE(test_cases[0]->Passed());
+ EXPECT_FALSE(test_cases[0]->Failed());
+
+ EXPECT_STREQ("DISABLED_Test", test_cases[1]->name());
+ EXPECT_STREQ("", test_cases[1]->comment());
+ EXPECT_FALSE(test_cases[1]->should_run());
+ EXPECT_EQ(1, test_cases[1]->disabled_test_count());
+ ASSERT_EQ(1, test_cases[1]->total_test_count());
+ EXPECT_EQ(0, test_cases[1]->successful_test_count());
+ EXPECT_EQ(0, test_cases[1]->failed_test_count());
+
+#if GTEST_HAS_TYPED_TEST
+ EXPECT_STREQ("TestCaseWithCommentTest/0", test_cases[2]->name());
+ EXPECT_STREQ(GetExpectedTestCaseComment().c_str(),
+ test_cases[2]->comment());
+ EXPECT_TRUE(test_cases[2]->should_run());
+ EXPECT_EQ(0, test_cases[2]->disabled_test_count());
+ ASSERT_EQ(1, test_cases[2]->total_test_count());
+ EXPECT_EQ(1, test_cases[2]->successful_test_count());
+ EXPECT_EQ(0, test_cases[2]->failed_test_count());
+ EXPECT_TRUE(test_cases[2]->Passed());
+ EXPECT_FALSE(test_cases[2]->Failed());
+#endif // GTEST_HAS_TYPED_TEST
+
+ const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest");
+ const TestInfo** tests = UnitTestHelper::GetSortedTests(test_case);
+ EXPECT_STREQ("DISABLED_Dummy1", tests[0]->name());
+ EXPECT_STREQ("ApiTest", tests[0]->test_case_name());
+ EXPECT_FALSE(tests[0]->should_run());
+
+ EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name());
+ EXPECT_STREQ("ApiTest", tests[1]->test_case_name());
+ EXPECT_STREQ("", tests[1]->comment());
+ EXPECT_STREQ("", tests[1]->test_case_comment());
+ EXPECT_TRUE(tests[1]->should_run());
+ EXPECT_TRUE(tests[1]->result()->Passed());
+ EXPECT_EQ(0, tests[1]->result()->test_property_count());
+
+ EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name());
+ EXPECT_STREQ("ApiTest", tests[2]->test_case_name());
+ EXPECT_STREQ("", tests[2]->comment());
+ EXPECT_STREQ("", tests[2]->test_case_comment());
+ EXPECT_TRUE(tests[2]->should_run());
+ EXPECT_TRUE(tests[2]->result()->Passed());
+ EXPECT_EQ(0, tests[2]->result()->test_property_count());
+
+ EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name());
+ EXPECT_STREQ("ApiTest", tests[3]->test_case_name());
+ EXPECT_STREQ("", tests[3]->comment());
+ EXPECT_STREQ("", tests[3]->test_case_comment());
+ EXPECT_TRUE(tests[3]->should_run());
+ EXPECT_TRUE(tests[3]->result()->Passed());
+ EXPECT_EQ(1, tests[3]->result()->test_property_count());
+ const TestProperty& property = tests[3]->result()->GetTestProperty(0);
+ EXPECT_STREQ("key", property.key());
+ EXPECT_STREQ("value", property.value());
+
+ delete[] tests;
+
+#if GTEST_HAS_TYPED_TEST
+ test_case = UnitTestHelper::FindTestCase("TestCaseWithCommentTest/0");
+ tests = UnitTestHelper::GetSortedTests(test_case);
+
+ EXPECT_STREQ("Dummy", tests[0]->name());
+ EXPECT_STREQ("TestCaseWithCommentTest/0", tests[0]->test_case_name());
+ EXPECT_STREQ("", tests[0]->comment());
+ EXPECT_STREQ(GetExpectedTestCaseComment().c_str(),
+ tests[0]->test_case_comment());
+ EXPECT_TRUE(tests[0]->should_run());
+ EXPECT_TRUE(tests[0]->result()->Passed());
+ EXPECT_EQ(0, tests[0]->result()->test_property_count());
+
+ delete[] tests;
+#endif // GTEST_HAS_TYPED_TEST
+ delete[] test_cases;
+ }
+};
+
+} // namespace internal
+} // namespace testing
+
+int main(int argc, char **argv) {
+ InitGoogleTest(&argc, argv);
+
+ AddGlobalTestEnvironment(new testing::internal::FinalSuccessChecker());
+
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_all_test.cc b/Source/ThirdParty/gtest/test/gtest_all_test.cc
new file mode 100644
index 000000000..e1edb08e3
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_all_test.cc
@@ -0,0 +1,48 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Tests for Google C++ Testing Framework (Google Test)
+//
+// Sometimes it's desirable to build most of Google Test's own tests
+// by compiling a single file. This file serves this purpose.
+#include "test/gtest-filepath_test.cc"
+#include "test/gtest-linked_ptr_test.cc"
+#include "test/gtest-message_test.cc"
+#include "test/gtest-options_test.cc"
+#include "test/gtest-port_test.cc"
+#include "test/gtest_pred_impl_unittest.cc"
+#include "test/gtest_prod_test.cc"
+#include "test/gtest-test-part_test.cc"
+#include "test/gtest-typed-test_test.cc"
+#include "test/gtest-typed-test2_test.cc"
+#include "test/gtest_unittest.cc"
+#include "test/production.cc"
+#include "src/gtest_main.cc"
diff --git a/Source/ThirdParty/gtest/test/gtest_break_on_failure_unittest.py b/Source/ThirdParty/gtest/test/gtest_break_on_failure_unittest.py
new file mode 100755
index 000000000..c81918331
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_break_on_failure_unittest.py
@@ -0,0 +1,218 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for Google Test's break-on-failure mode.
+
+A user can ask Google Test to seg-fault when an assertion fails, using
+either the GTEST_BREAK_ON_FAILURE environment variable or the
+--gtest_break_on_failure flag. This script tests such functionality
+by invoking gtest_break_on_failure_unittest_ (a program written with
+Google Test) with different environments and command line flags.
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import gtest_test_utils
+import os
+import sys
+
+
+# Constants.
+
+IS_WINDOWS = os.name == 'nt'
+
+# The environment variable for enabling/disabling the break-on-failure mode.
+BREAK_ON_FAILURE_ENV_VAR = 'GTEST_BREAK_ON_FAILURE'
+
+# The command line flag for enabling/disabling the break-on-failure mode.
+BREAK_ON_FAILURE_FLAG = 'gtest_break_on_failure'
+
+# The environment variable for enabling/disabling the throw-on-failure mode.
+THROW_ON_FAILURE_ENV_VAR = 'GTEST_THROW_ON_FAILURE'
+
+# The environment variable for enabling/disabling the catch-exceptions mode.
+CATCH_EXCEPTIONS_ENV_VAR = 'GTEST_CATCH_EXCEPTIONS'
+
+# Path to the gtest_break_on_failure_unittest_ program.
+EXE_PATH = gtest_test_utils.GetTestExecutablePath(
+ 'gtest_break_on_failure_unittest_')
+
+
+# Utilities.
+
+
+environ = os.environ.copy()
+
+
+def SetEnvVar(env_var, value):
+ """Sets an environment variable to a given value; unsets it when the
+ given value is None.
+ """
+
+ if value is not None:
+ environ[env_var] = value
+ elif env_var in environ:
+ del environ[env_var]
+
+
+def Run(command):
+ """Runs a command; returns 1 if it was killed by a signal, or 0 otherwise."""
+
+ p = gtest_test_utils.Subprocess(command, env=environ)
+ if p.terminated_by_signal:
+ return 1
+ else:
+ return 0
+
+
+# The tests.
+
+
+class GTestBreakOnFailureUnitTest(gtest_test_utils.TestCase):
+ """Tests using the GTEST_BREAK_ON_FAILURE environment variable or
+ the --gtest_break_on_failure flag to turn assertion failures into
+ segmentation faults.
+ """
+
+ def RunAndVerify(self, env_var_value, flag_value, expect_seg_fault):
+ """Runs gtest_break_on_failure_unittest_ and verifies that it does
+ (or does not) have a seg-fault.
+
+ Args:
+ env_var_value: value of the GTEST_BREAK_ON_FAILURE environment
+ variable; None if the variable should be unset.
+ flag_value: value of the --gtest_break_on_failure flag;
+ None if the flag should not be present.
+ expect_seg_fault: 1 if the program is expected to generate a seg-fault;
+ 0 otherwise.
+ """
+
+ SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, env_var_value)
+
+ if env_var_value is None:
+ env_var_value_msg = ' is not set'
+ else:
+ env_var_value_msg = '=' + env_var_value
+
+ if flag_value is None:
+ flag = ''
+ elif flag_value == '0':
+ flag = '--%s=0' % BREAK_ON_FAILURE_FLAG
+ else:
+ flag = '--%s' % BREAK_ON_FAILURE_FLAG
+
+ command = [EXE_PATH]
+ if flag:
+ command.append(flag)
+
+ if expect_seg_fault:
+ should_or_not = 'should'
+ else:
+ should_or_not = 'should not'
+
+ has_seg_fault = Run(command)
+
+ SetEnvVar(BREAK_ON_FAILURE_ENV_VAR, None)
+
+ msg = ('when %s%s, an assertion failure in "%s" %s cause a seg-fault.' %
+ (BREAK_ON_FAILURE_ENV_VAR, env_var_value_msg, ' '.join(command),
+ should_or_not))
+ self.assert_(has_seg_fault == expect_seg_fault, msg)
+
+ def testDefaultBehavior(self):
+ """Tests the behavior of the default mode."""
+
+ self.RunAndVerify(env_var_value=None,
+ flag_value=None,
+ expect_seg_fault=0)
+
+ def testEnvVar(self):
+ """Tests using the GTEST_BREAK_ON_FAILURE environment variable."""
+
+ self.RunAndVerify(env_var_value='0',
+ flag_value=None,
+ expect_seg_fault=0)
+ self.RunAndVerify(env_var_value='1',
+ flag_value=None,
+ expect_seg_fault=1)
+
+ def testFlag(self):
+ """Tests using the --gtest_break_on_failure flag."""
+
+ self.RunAndVerify(env_var_value=None,
+ flag_value='0',
+ expect_seg_fault=0)
+ self.RunAndVerify(env_var_value=None,
+ flag_value='1',
+ expect_seg_fault=1)
+
+ def testFlagOverridesEnvVar(self):
+ """Tests that the flag overrides the environment variable."""
+
+ self.RunAndVerify(env_var_value='0',
+ flag_value='0',
+ expect_seg_fault=0)
+ self.RunAndVerify(env_var_value='0',
+ flag_value='1',
+ expect_seg_fault=1)
+ self.RunAndVerify(env_var_value='1',
+ flag_value='0',
+ expect_seg_fault=0)
+ self.RunAndVerify(env_var_value='1',
+ flag_value='1',
+ expect_seg_fault=1)
+
+ def testBreakOnFailureOverridesThrowOnFailure(self):
+ """Tests that gtest_break_on_failure overrides gtest_throw_on_failure."""
+
+ SetEnvVar(THROW_ON_FAILURE_ENV_VAR, '1')
+ try:
+ self.RunAndVerify(env_var_value=None,
+ flag_value='1',
+ expect_seg_fault=1)
+ finally:
+ SetEnvVar(THROW_ON_FAILURE_ENV_VAR, None)
+
+ if IS_WINDOWS:
+ def testCatchExceptionsDoesNotInterfere(self):
+ """Tests that gtest_catch_exceptions doesn't interfere."""
+
+ SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, '1')
+ try:
+ self.RunAndVerify(env_var_value='1',
+ flag_value='1',
+ expect_seg_fault=1)
+ finally:
+ SetEnvVar(CATCH_EXCEPTIONS_ENV_VAR, None)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_break_on_failure_unittest_.cc b/Source/ThirdParty/gtest/test/gtest_break_on_failure_unittest_.cc
new file mode 100644
index 000000000..d28d1d3da
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_break_on_failure_unittest_.cc
@@ -0,0 +1,86 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Unit test for Google Test's break-on-failure mode.
+//
+// A user can ask Google Test to seg-fault when an assertion fails, using
+// either the GTEST_BREAK_ON_FAILURE environment variable or the
+// --gtest_break_on_failure flag. This file is used for testing such
+// functionality.
+//
+// This program will be invoked from a Python unit test. It is
+// expected to fail. Don't run it directly.
+
+#include <gtest/gtest.h>
+
+#if GTEST_OS_WINDOWS
+#include <windows.h>
+#include <stdlib.h>
+#endif
+
+namespace {
+
+// A test that's expected to fail.
+TEST(Foo, Bar) {
+ EXPECT_EQ(2, 3);
+}
+
+#if GTEST_HAS_SEH && !GTEST_OS_WINDOWS_MOBILE
+// On Windows Mobile global exception handlers are not supported.
+LONG WINAPI ExitWithExceptionCode(
+ struct _EXCEPTION_POINTERS* exception_pointers) {
+ exit(exception_pointers->ExceptionRecord->ExceptionCode);
+}
+#endif
+
+} // namespace
+
+int main(int argc, char **argv) {
+#if GTEST_OS_WINDOWS
+ // Suppresses display of the Windows error dialog upon encountering
+ // a general protection fault (segment violation).
+ SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS);
+
+#if !GTEST_OS_WINDOWS_MOBILE
+ // The default unhandled exception filter does not always exit
+ // with the exception code as exit code - for example it exits with
+ // 0 for EXCEPTION_ACCESS_VIOLATION and 1 for EXCEPTION_BREAKPOINT
+ // if the application is compiled in debug mode. Thus we use our own
+ // filter which always exits with the exception code for unhandled
+ // exceptions.
+ SetUnhandledExceptionFilter(ExitWithExceptionCode);
+#endif
+#endif
+
+ testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_color_test.py b/Source/ThirdParty/gtest/test/gtest_color_test.py
new file mode 100755
index 000000000..d02a53ed8
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_color_test.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Verifies that Google Test correctly determines whether to use colors."""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import gtest_test_utils
+
+
+IS_WINDOWS = os.name = 'nt'
+
+COLOR_ENV_VAR = 'GTEST_COLOR'
+COLOR_FLAG = 'gtest_color'
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_color_test_')
+
+
+def SetEnvVar(env_var, value):
+ """Sets the env variable to 'value'; unsets it when 'value' is None."""
+
+ if value is not None:
+ os.environ[env_var] = value
+ elif env_var in os.environ:
+ del os.environ[env_var]
+
+
+def UsesColor(term, color_env_var, color_flag):
+ """Runs gtest_color_test_ and returns its exit code."""
+
+ SetEnvVar('TERM', term)
+ SetEnvVar(COLOR_ENV_VAR, color_env_var)
+
+ if color_flag is None:
+ args = []
+ else:
+ args = ['--%s=%s' % (COLOR_FLAG, color_flag)]
+ p = gtest_test_utils.Subprocess([COMMAND] + args)
+ return not p.exited or p.exit_code
+
+
+class GTestColorTest(gtest_test_utils.TestCase):
+ def testNoEnvVarNoFlag(self):
+ """Tests the case when there's neither GTEST_COLOR nor --gtest_color."""
+
+ if not IS_WINDOWS:
+ self.assert_(not UsesColor('dumb', None, None))
+ self.assert_(not UsesColor('emacs', None, None))
+ self.assert_(not UsesColor('xterm-mono', None, None))
+ self.assert_(not UsesColor('unknown', None, None))
+ self.assert_(not UsesColor(None, None, None))
+ self.assert_(UsesColor('linux', None, None))
+ self.assert_(UsesColor('cygwin', None, None))
+ self.assert_(UsesColor('xterm', None, None))
+ self.assert_(UsesColor('xterm-color', None, None))
+ self.assert_(UsesColor('xterm-256color', None, None))
+
+ def testFlagOnly(self):
+ """Tests the case when there's --gtest_color but not GTEST_COLOR."""
+
+ self.assert_(not UsesColor('dumb', None, 'no'))
+ self.assert_(not UsesColor('xterm-color', None, 'no'))
+ if not IS_WINDOWS:
+ self.assert_(not UsesColor('emacs', None, 'auto'))
+ self.assert_(UsesColor('xterm', None, 'auto'))
+ self.assert_(UsesColor('dumb', None, 'yes'))
+ self.assert_(UsesColor('xterm', None, 'yes'))
+
+ def testEnvVarOnly(self):
+ """Tests the case when there's GTEST_COLOR but not --gtest_color."""
+
+ self.assert_(not UsesColor('dumb', 'no', None))
+ self.assert_(not UsesColor('xterm-color', 'no', None))
+ if not IS_WINDOWS:
+ self.assert_(not UsesColor('dumb', 'auto', None))
+ self.assert_(UsesColor('xterm-color', 'auto', None))
+ self.assert_(UsesColor('dumb', 'yes', None))
+ self.assert_(UsesColor('xterm-color', 'yes', None))
+
+ def testEnvVarAndFlag(self):
+ """Tests the case when there are both GTEST_COLOR and --gtest_color."""
+
+ self.assert_(not UsesColor('xterm-color', 'no', 'no'))
+ self.assert_(UsesColor('dumb', 'no', 'yes'))
+ self.assert_(UsesColor('xterm-color', 'no', 'auto'))
+
+ def testAliasesOfYesAndNo(self):
+ """Tests using aliases in specifying --gtest_color."""
+
+ self.assert_(UsesColor('dumb', None, 'true'))
+ self.assert_(UsesColor('dumb', None, 'YES'))
+ self.assert_(UsesColor('dumb', None, 'T'))
+ self.assert_(UsesColor('dumb', None, '1'))
+
+ self.assert_(not UsesColor('xterm', None, 'f'))
+ self.assert_(not UsesColor('xterm', None, 'false'))
+ self.assert_(not UsesColor('xterm', None, '0'))
+ self.assert_(not UsesColor('xterm', None, 'unknown'))
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_color_test_.cc b/Source/ThirdParty/gtest/test/gtest_color_test_.cc
new file mode 100644
index 000000000..58d377c9b
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_color_test_.cc
@@ -0,0 +1,71 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// A helper program for testing how Google Test determines whether to use
+// colors in the output. It prints "YES" and returns 1 if Google Test
+// decides to use colors, and prints "NO" and returns 0 otherwise.
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+using testing::internal::ShouldUseColor;
+
+// The purpose of this is to ensure that the UnitTest singleton is
+// created before main() is entered, and thus that ShouldUseColor()
+// works the same way as in a real Google-Test-based test. We don't actual
+// run the TEST itself.
+TEST(GTestColorTest, Dummy) {
+}
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+
+ if (ShouldUseColor(true)) {
+ // Google Test decides to use colors in the output (assuming it
+ // goes to a TTY).
+ printf("YES\n");
+ return 1;
+ } else {
+ // Google Test decides not to use colors in the output.
+ printf("NO\n");
+ return 0;
+ }
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_env_var_test.py b/Source/ThirdParty/gtest/test/gtest_env_var_test.py
new file mode 100755
index 000000000..bcc0bfd55
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_env_var_test.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Verifies that Google Test correctly parses environment variables."""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import gtest_test_utils
+
+
+IS_WINDOWS = os.name == 'nt'
+IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux'
+
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_env_var_test_')
+
+environ = os.environ.copy()
+
+
+def AssertEq(expected, actual):
+ if expected != actual:
+ print 'Expected: %s' % (expected,)
+ print ' Actual: %s' % (actual,)
+ raise AssertionError
+
+
+def SetEnvVar(env_var, value):
+ """Sets the env variable to 'value'; unsets it when 'value' is None."""
+
+ if value is not None:
+ environ[env_var] = value
+ elif env_var in environ:
+ del environ[env_var]
+
+
+def GetFlag(flag):
+ """Runs gtest_env_var_test_ and returns its output."""
+
+ args = [COMMAND]
+ if flag is not None:
+ args += [flag]
+ return gtest_test_utils.Subprocess(args, env=environ).output
+
+
+def TestFlag(flag, test_val, default_val):
+ """Verifies that the given flag is affected by the corresponding env var."""
+
+ env_var = 'GTEST_' + flag.upper()
+ SetEnvVar(env_var, test_val)
+ AssertEq(test_val, GetFlag(flag))
+ SetEnvVar(env_var, None)
+ AssertEq(default_val, GetFlag(flag))
+
+
+class GTestEnvVarTest(gtest_test_utils.TestCase):
+ def testEnvVarAffectsFlag(self):
+ """Tests that environment variable should affect the corresponding flag."""
+
+ TestFlag('break_on_failure', '1', '0')
+ TestFlag('color', 'yes', 'auto')
+ TestFlag('filter', 'FooTest.Bar', '*')
+ TestFlag('output', 'xml:tmp/foo.xml', '')
+ TestFlag('print_time', '0', '1')
+ TestFlag('repeat', '999', '1')
+ TestFlag('throw_on_failure', '1', '0')
+ TestFlag('death_test_style', 'threadsafe', 'fast')
+
+ if IS_WINDOWS:
+ TestFlag('catch_exceptions', '1', '0')
+
+ if IS_LINUX:
+ TestFlag('death_test_use_fork', '1', '0')
+ TestFlag('stack_trace_depth', '0', '100')
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_env_var_test_.cc b/Source/ThirdParty/gtest/test/gtest_env_var_test_.cc
new file mode 100644
index 000000000..f7c78fcf3
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_env_var_test_.cc
@@ -0,0 +1,126 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// A helper program for testing that Google Test parses the environment
+// variables correctly.
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+using ::std::cout;
+
+namespace testing {
+
+// The purpose of this is to make the test more realistic by ensuring
+// that the UnitTest singleton is created before main() is entered.
+// We don't actual run the TEST itself.
+TEST(GTestEnvVarTest, Dummy) {
+}
+
+void PrintFlag(const char* flag) {
+ if (strcmp(flag, "break_on_failure") == 0) {
+ cout << GTEST_FLAG(break_on_failure);
+ return;
+ }
+
+ if (strcmp(flag, "catch_exceptions") == 0) {
+ cout << GTEST_FLAG(catch_exceptions);
+ return;
+ }
+
+ if (strcmp(flag, "color") == 0) {
+ cout << GTEST_FLAG(color);
+ return;
+ }
+
+ if (strcmp(flag, "death_test_style") == 0) {
+ cout << GTEST_FLAG(death_test_style);
+ return;
+ }
+
+ if (strcmp(flag, "death_test_use_fork") == 0) {
+ cout << GTEST_FLAG(death_test_use_fork);
+ return;
+ }
+
+ if (strcmp(flag, "filter") == 0) {
+ cout << GTEST_FLAG(filter);
+ return;
+ }
+
+ if (strcmp(flag, "output") == 0) {
+ cout << GTEST_FLAG(output);
+ return;
+ }
+
+ if (strcmp(flag, "print_time") == 0) {
+ cout << GTEST_FLAG(print_time);
+ return;
+ }
+
+ if (strcmp(flag, "repeat") == 0) {
+ cout << GTEST_FLAG(repeat);
+ return;
+ }
+
+ if (strcmp(flag, "stack_trace_depth") == 0) {
+ cout << GTEST_FLAG(stack_trace_depth);
+ return;
+ }
+
+ if (strcmp(flag, "throw_on_failure") == 0) {
+ cout << GTEST_FLAG(throw_on_failure);
+ return;
+ }
+
+ cout << "Invalid flag name " << flag
+ << ". Valid names are break_on_failure, color, filter, etc.\n";
+ exit(1);
+}
+
+} // namespace testing
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+
+ if (argc != 2) {
+ cout << "Usage: gtest_env_var_test_ NAME_OF_FLAG\n";
+ return 1;
+ }
+
+ testing::PrintFlag(argv[1]);
+ return 0;
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_environment_test.cc b/Source/ThirdParty/gtest/test/gtest_environment_test.cc
new file mode 100644
index 000000000..c9392614d
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_environment_test.cc
@@ -0,0 +1,186 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Tests using global test environments.
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <gtest/gtest.h>
+
+namespace testing {
+GTEST_DECLARE_string_(filter);
+}
+
+namespace {
+
+enum FailureType {
+ NO_FAILURE, NON_FATAL_FAILURE, FATAL_FAILURE
+};
+
+// For testing using global test environments.
+class MyEnvironment : public testing::Environment {
+ public:
+ MyEnvironment() { Reset(); }
+
+ // Depending on the value of failure_in_set_up_, SetUp() will
+ // generate a non-fatal failure, generate a fatal failure, or
+ // succeed.
+ virtual void SetUp() {
+ set_up_was_run_ = true;
+
+ switch (failure_in_set_up_) {
+ case NON_FATAL_FAILURE:
+ ADD_FAILURE() << "Expected non-fatal failure in global set-up.";
+ break;
+ case FATAL_FAILURE:
+ FAIL() << "Expected fatal failure in global set-up.";
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Generates a non-fatal failure.
+ virtual void TearDown() {
+ tear_down_was_run_ = true;
+ ADD_FAILURE() << "Expected non-fatal failure in global tear-down.";
+ }
+
+ // Resets the state of the environment s.t. it can be reused.
+ void Reset() {
+ failure_in_set_up_ = NO_FAILURE;
+ set_up_was_run_ = false;
+ tear_down_was_run_ = false;
+ }
+
+ // We call this function to set the type of failure SetUp() should
+ // generate.
+ void set_failure_in_set_up(FailureType type) {
+ failure_in_set_up_ = type;
+ }
+
+ // Was SetUp() run?
+ bool set_up_was_run() const { return set_up_was_run_; }
+
+ // Was TearDown() run?
+ bool tear_down_was_run() const { return tear_down_was_run_; }
+ private:
+ FailureType failure_in_set_up_;
+ bool set_up_was_run_;
+ bool tear_down_was_run_;
+};
+
+// Was the TEST run?
+bool test_was_run;
+
+// The sole purpose of this TEST is to enable us to check whether it
+// was run.
+TEST(FooTest, Bar) {
+ test_was_run = true;
+}
+
+// Prints the message and aborts the program if condition is false.
+void Check(bool condition, const char* msg) {
+ if (!condition) {
+ printf("FAILED: %s\n", msg);
+ abort();
+ }
+}
+
+// Runs the tests. Return true iff successful.
+//
+// The 'failure' parameter specifies the type of failure that should
+// be generated by the global set-up.
+int RunAllTests(MyEnvironment* env, FailureType failure) {
+ env->Reset();
+ env->set_failure_in_set_up(failure);
+ test_was_run = false;
+ return RUN_ALL_TESTS();
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+
+ // Registers a global test environment, and verifies that the
+ // registration function returns its argument.
+ MyEnvironment* const env = new MyEnvironment;
+ Check(testing::AddGlobalTestEnvironment(env) == env,
+ "AddGlobalTestEnvironment() should return its argument.");
+
+ // Verifies that RUN_ALL_TESTS() runs the tests when the global
+ // set-up is successful.
+ Check(RunAllTests(env, NO_FAILURE) != 0,
+ "RUN_ALL_TESTS() should return non-zero, as the global tear-down "
+ "should generate a failure.");
+ Check(test_was_run,
+ "The tests should run, as the global set-up should generate no "
+ "failure");
+ Check(env->tear_down_was_run(),
+ "The global tear-down should run, as the global set-up was run.");
+
+ // Verifies that RUN_ALL_TESTS() runs the tests when the global
+ // set-up generates no fatal failure.
+ Check(RunAllTests(env, NON_FATAL_FAILURE) != 0,
+ "RUN_ALL_TESTS() should return non-zero, as both the global set-up "
+ "and the global tear-down should generate a non-fatal failure.");
+ Check(test_was_run,
+ "The tests should run, as the global set-up should generate no "
+ "fatal failure.");
+ Check(env->tear_down_was_run(),
+ "The global tear-down should run, as the global set-up was run.");
+
+ // Verifies that RUN_ALL_TESTS() runs no test when the global set-up
+ // generates a fatal failure.
+ Check(RunAllTests(env, FATAL_FAILURE) != 0,
+ "RUN_ALL_TESTS() should return non-zero, as the global set-up "
+ "should generate a fatal failure.");
+ Check(!test_was_run,
+ "The tests should not run, as the global set-up should generate "
+ "a fatal failure.");
+ Check(env->tear_down_was_run(),
+ "The global tear-down should run, as the global set-up was run.");
+
+ // Verifies that RUN_ALL_TESTS() doesn't do global set-up or
+ // tear-down when there is no test to run.
+ testing::GTEST_FLAG(filter) = "-*";
+ Check(RunAllTests(env, NO_FAILURE) == 0,
+ "RUN_ALL_TESTS() should return zero, as there is no test to run.");
+ Check(!env->set_up_was_run(),
+ "The global set-up should not run, as there is no test to run.");
+ Check(!env->tear_down_was_run(),
+ "The global tear-down should not run, "
+ "as the global set-up was not run.");
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_filter_unittest.py b/Source/ThirdParty/gtest/test/gtest_filter_unittest.py
new file mode 100755
index 000000000..0d1a77005
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_filter_unittest.py
@@ -0,0 +1,633 @@
+#!/usr/bin/env python
+#
+# Copyright 2005 Google Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for Google Test test filters.
+
+A user can specify which test(s) in a Google Test program to run via either
+the GTEST_FILTER environment variable or the --gtest_filter flag.
+This script tests such functionality by invoking
+gtest_filter_unittest_ (a program written with Google Test) with different
+environments and command line flags.
+
+Note that test sharding may also influence which tests are filtered. Therefore,
+we test that here also.
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import re
+import sets
+import sys
+
+import gtest_test_utils
+
+# Constants.
+
+# Checks if this platform can pass empty environment variables to child
+# processes. We set an env variable to an empty string and invoke a python
+# script in a subprocess to print whether the variable is STILL in
+# os.environ. We then use 'eval' to parse the child's output so that an
+# exception is thrown if the input is anything other than 'True' nor 'False'.
+os.environ['EMPTY_VAR'] = ''
+child = gtest_test_utils.Subprocess(
+ [sys.executable, '-c', 'import os; print \'EMPTY_VAR\' in os.environ'])
+CAN_PASS_EMPTY_ENV = eval(child.output)
+
+
+# Check if this platform can unset environment variables in child processes.
+# We set an env variable to a non-empty string, unset it, and invoke
+# a python script in a subprocess to print whether the variable
+# is NO LONGER in os.environ.
+# We use 'eval' to parse the child's output so that an exception
+# is thrown if the input is neither 'True' nor 'False'.
+os.environ['UNSET_VAR'] = 'X'
+del os.environ['UNSET_VAR']
+child = gtest_test_utils.Subprocess(
+ [sys.executable, '-c', 'import os; print \'UNSET_VAR\' not in os.environ'])
+CAN_UNSET_ENV = eval(child.output)
+
+
+# Checks if we should test with an empty filter. This doesn't
+# make sense on platforms that cannot pass empty env variables (Win32)
+# and on platforms that cannot unset variables (since we cannot tell
+# the difference between "" and NULL -- Borland and Solaris < 5.10)
+CAN_TEST_EMPTY_FILTER = (CAN_PASS_EMPTY_ENV and CAN_UNSET_ENV)
+
+
+# The environment variable for specifying the test filters.
+FILTER_ENV_VAR = 'GTEST_FILTER'
+
+# The environment variables for test sharding.
+TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS'
+SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
+SHARD_STATUS_FILE_ENV_VAR = 'GTEST_SHARD_STATUS_FILE'
+
+# The command line flag for specifying the test filters.
+FILTER_FLAG = 'gtest_filter'
+
+# The command line flag for including disabled tests.
+ALSO_RUN_DISABED_TESTS_FLAG = 'gtest_also_run_disabled_tests'
+
+# Command to run the gtest_filter_unittest_ program.
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_filter_unittest_')
+
+# Regex for determining whether parameterized tests are enabled in the binary.
+PARAM_TEST_REGEX = re.compile(r'/ParamTest')
+
+# Regex for parsing test case names from Google Test's output.
+TEST_CASE_REGEX = re.compile(r'^\[\-+\] \d+ tests? from (\w+(/\w+)?)')
+
+# Regex for parsing test names from Google Test's output.
+TEST_REGEX = re.compile(r'^\[\s*RUN\s*\].*\.(\w+(/\w+)?)')
+
+# The command line flag to tell Google Test to output the list of tests it
+# will run.
+LIST_TESTS_FLAG = '--gtest_list_tests'
+
+# Indicates whether Google Test supports death tests.
+SUPPORTS_DEATH_TESTS = 'HasDeathTest' in gtest_test_utils.Subprocess(
+ [COMMAND, LIST_TESTS_FLAG]).output
+
+# Full names of all tests in gtest_filter_unittests_.
+PARAM_TESTS = [
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestX/1',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqP/ParamTest.TestY/1',
+ 'SeqQ/ParamTest.TestX/0',
+ 'SeqQ/ParamTest.TestX/1',
+ 'SeqQ/ParamTest.TestY/0',
+ 'SeqQ/ParamTest.TestY/1',
+ ]
+
+DISABLED_TESTS = [
+ 'BarTest.DISABLED_TestFour',
+ 'BarTest.DISABLED_TestFive',
+ 'BazTest.DISABLED_TestC',
+ 'DISABLED_FoobarTest.Test1',
+ 'DISABLED_FoobarTest.DISABLED_Test2',
+ 'DISABLED_FoobarbazTest.TestA',
+ ]
+
+if SUPPORTS_DEATH_TESTS:
+ DEATH_TESTS = [
+ 'HasDeathTest.Test1',
+ 'HasDeathTest.Test2',
+ ]
+else:
+ DEATH_TESTS = []
+
+# All the non-disabled tests.
+ACTIVE_TESTS = [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+
+ 'BazTest.TestOne',
+ 'BazTest.TestA',
+ 'BazTest.TestB',
+ ] + DEATH_TESTS + PARAM_TESTS
+
+param_tests_present = None
+
+# Utilities.
+
+environ = os.environ.copy()
+
+
+def SetEnvVar(env_var, value):
+ """Sets the env variable to 'value'; unsets it when 'value' is None."""
+
+ if value is not None:
+ environ[env_var] = value
+ elif env_var in environ:
+ del environ[env_var]
+
+
+def RunAndReturnOutput(args = None):
+ """Runs the test program and returns its output."""
+
+ return gtest_test_utils.Subprocess([COMMAND] + (args or []),
+ env=environ).output
+
+
+def RunAndExtractTestList(args = None):
+ """Runs the test program and returns its exit code and a list of tests run."""
+
+ p = gtest_test_utils.Subprocess([COMMAND] + (args or []), env=environ)
+ tests_run = []
+ test_case = ''
+ test = ''
+ for line in p.output.split('\n'):
+ match = TEST_CASE_REGEX.match(line)
+ if match is not None:
+ test_case = match.group(1)
+ else:
+ match = TEST_REGEX.match(line)
+ if match is not None:
+ test = match.group(1)
+ tests_run.append(test_case + '.' + test)
+ return (tests_run, p.exit_code)
+
+
+def InvokeWithModifiedEnv(extra_env, function, *args, **kwargs):
+ """Runs the given function and arguments in a modified environment."""
+ try:
+ original_env = environ.copy()
+ environ.update(extra_env)
+ return function(*args, **kwargs)
+ finally:
+ environ.clear()
+ environ.update(original_env)
+
+
+def RunWithSharding(total_shards, shard_index, command):
+ """Runs a test program shard and returns exit code and a list of tests run."""
+
+ extra_env = {SHARD_INDEX_ENV_VAR: str(shard_index),
+ TOTAL_SHARDS_ENV_VAR: str(total_shards)}
+ return InvokeWithModifiedEnv(extra_env, RunAndExtractTestList, command)
+
+# The unit test.
+
+
+class GTestFilterUnitTest(gtest_test_utils.TestCase):
+ """Tests the env variable or the command line flag to filter tests."""
+
+ # Utilities.
+
+ def AssertSetEqual(self, lhs, rhs):
+ """Asserts that two sets are equal."""
+
+ for elem in lhs:
+ self.assert_(elem in rhs, '%s in %s' % (elem, rhs))
+
+ for elem in rhs:
+ self.assert_(elem in lhs, '%s in %s' % (elem, lhs))
+
+ def AssertPartitionIsValid(self, set_var, list_of_sets):
+ """Asserts that list_of_sets is a valid partition of set_var."""
+
+ full_partition = []
+ for slice_var in list_of_sets:
+ full_partition.extend(slice_var)
+ self.assertEqual(len(set_var), len(full_partition))
+ self.assertEqual(sets.Set(set_var), sets.Set(full_partition))
+
+ def AdjustForParameterizedTests(self, tests_to_run):
+ """Adjust tests_to_run in case value parameterized tests are disabled."""
+
+ global param_tests_present
+ if not param_tests_present:
+ return list(sets.Set(tests_to_run) - sets.Set(PARAM_TESTS))
+ else:
+ return tests_to_run
+
+ def RunAndVerify(self, gtest_filter, tests_to_run):
+ """Checks that the binary runs correct set of tests for a given filter."""
+
+ tests_to_run = self.AdjustForParameterizedTests(tests_to_run)
+
+ # First, tests using the environment variable.
+
+ # Windows removes empty variables from the environment when passing it
+ # to a new process. This means it is impossible to pass an empty filter
+ # into a process using the environment variable. However, we can still
+ # test the case when the variable is not supplied (i.e., gtest_filter is
+ # None).
+ # pylint: disable-msg=C6403
+ if CAN_TEST_EMPTY_FILTER or gtest_filter != '':
+ SetEnvVar(FILTER_ENV_VAR, gtest_filter)
+ tests_run = RunAndExtractTestList()[0]
+ SetEnvVar(FILTER_ENV_VAR, None)
+ self.AssertSetEqual(tests_run, tests_to_run)
+ # pylint: enable-msg=C6403
+
+ # Next, tests using the command line flag.
+
+ if gtest_filter is None:
+ args = []
+ else:
+ args = ['--%s=%s' % (FILTER_FLAG, gtest_filter)]
+
+ tests_run = RunAndExtractTestList(args)[0]
+ self.AssertSetEqual(tests_run, tests_to_run)
+
+ def RunAndVerifyWithSharding(self, gtest_filter, total_shards, tests_to_run,
+ args=None, check_exit_0=False):
+ """Checks that binary runs correct tests for the given filter and shard.
+
+ Runs all shards of gtest_filter_unittest_ with the given filter, and
+ verifies that the right set of tests were run. The union of tests run
+ on each shard should be identical to tests_to_run, without duplicates.
+
+ Args:
+ gtest_filter: A filter to apply to the tests.
+ total_shards: A total number of shards to split test run into.
+ tests_to_run: A set of tests expected to run.
+ args : Arguments to pass to the to the test binary.
+ check_exit_0: When set to a true value, make sure that all shards
+ return 0.
+ """
+
+ tests_to_run = self.AdjustForParameterizedTests(tests_to_run)
+
+ # Windows removes empty variables from the environment when passing it
+ # to a new process. This means it is impossible to pass an empty filter
+ # into a process using the environment variable. However, we can still
+ # test the case when the variable is not supplied (i.e., gtest_filter is
+ # None).
+ # pylint: disable-msg=C6403
+ if CAN_TEST_EMPTY_FILTER or gtest_filter != '':
+ SetEnvVar(FILTER_ENV_VAR, gtest_filter)
+ partition = []
+ for i in range(0, total_shards):
+ (tests_run, exit_code) = RunWithSharding(total_shards, i, args)
+ if check_exit_0:
+ self.assertEqual(0, exit_code)
+ partition.append(tests_run)
+
+ self.AssertPartitionIsValid(tests_to_run, partition)
+ SetEnvVar(FILTER_ENV_VAR, None)
+ # pylint: enable-msg=C6403
+
+ def RunAndVerifyAllowingDisabled(self, gtest_filter, tests_to_run):
+ """Checks that the binary runs correct set of tests for the given filter.
+
+ Runs gtest_filter_unittest_ with the given filter, and enables
+ disabled tests. Verifies that the right set of tests were run.
+
+ Args:
+ gtest_filter: A filter to apply to the tests.
+ tests_to_run: A set of tests expected to run.
+ """
+
+ tests_to_run = self.AdjustForParameterizedTests(tests_to_run)
+
+ # Construct the command line.
+ args = ['--%s' % ALSO_RUN_DISABED_TESTS_FLAG]
+ if gtest_filter is not None:
+ args.append('--%s=%s' % (FILTER_FLAG, gtest_filter))
+
+ tests_run = RunAndExtractTestList(args)[0]
+ self.AssertSetEqual(tests_run, tests_to_run)
+
+ def setUp(self):
+ """Sets up test case.
+
+ Determines whether value-parameterized tests are enabled in the binary and
+ sets the flags accordingly.
+ """
+
+ global param_tests_present
+ if param_tests_present is None:
+ param_tests_present = PARAM_TEST_REGEX.search(
+ RunAndReturnOutput()) is not None
+
+ def testDefaultBehavior(self):
+ """Tests the behavior of not specifying the filter."""
+
+ self.RunAndVerify(None, ACTIVE_TESTS)
+
+ def testDefaultBehaviorWithShards(self):
+ """Tests the behavior without the filter, with sharding enabled."""
+
+ self.RunAndVerifyWithSharding(None, 1, ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding(None, 2, ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) - 1, ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS), ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding(None, len(ACTIVE_TESTS) + 1, ACTIVE_TESTS)
+
+ def testEmptyFilter(self):
+ """Tests an empty filter."""
+
+ self.RunAndVerify('', [])
+ self.RunAndVerifyWithSharding('', 1, [])
+ self.RunAndVerifyWithSharding('', 2, [])
+
+ def testBadFilter(self):
+ """Tests a filter that matches nothing."""
+
+ self.RunAndVerify('BadFilter', [])
+ self.RunAndVerifyAllowingDisabled('BadFilter', [])
+
+ def testFullName(self):
+ """Tests filtering by full name."""
+
+ self.RunAndVerify('FooTest.Xyz', ['FooTest.Xyz'])
+ self.RunAndVerifyAllowingDisabled('FooTest.Xyz', ['FooTest.Xyz'])
+ self.RunAndVerifyWithSharding('FooTest.Xyz', 5, ['FooTest.Xyz'])
+
+ def testUniversalFilters(self):
+ """Tests filters that match everything."""
+
+ self.RunAndVerify('*', ACTIVE_TESTS)
+ self.RunAndVerify('*.*', ACTIVE_TESTS)
+ self.RunAndVerifyWithSharding('*.*', len(ACTIVE_TESTS) - 3, ACTIVE_TESTS)
+ self.RunAndVerifyAllowingDisabled('*', ACTIVE_TESTS + DISABLED_TESTS)
+ self.RunAndVerifyAllowingDisabled('*.*', ACTIVE_TESTS + DISABLED_TESTS)
+
+ def testFilterByTestCase(self):
+ """Tests filtering by test case name."""
+
+ self.RunAndVerify('FooTest.*', ['FooTest.Abc', 'FooTest.Xyz'])
+
+ BAZ_TESTS = ['BazTest.TestOne', 'BazTest.TestA', 'BazTest.TestB']
+ self.RunAndVerify('BazTest.*', BAZ_TESTS)
+ self.RunAndVerifyAllowingDisabled('BazTest.*',
+ BAZ_TESTS + ['BazTest.DISABLED_TestC'])
+
+ def testFilterByTest(self):
+ """Tests filtering by test name."""
+
+ self.RunAndVerify('*.TestOne', ['BarTest.TestOne', 'BazTest.TestOne'])
+
+ def testFilterDisabledTests(self):
+ """Select only the disabled tests to run."""
+
+ self.RunAndVerify('DISABLED_FoobarTest.Test1', [])
+ self.RunAndVerifyAllowingDisabled('DISABLED_FoobarTest.Test1',
+ ['DISABLED_FoobarTest.Test1'])
+
+ self.RunAndVerify('*DISABLED_*', [])
+ self.RunAndVerifyAllowingDisabled('*DISABLED_*', DISABLED_TESTS)
+
+ self.RunAndVerify('*.DISABLED_*', [])
+ self.RunAndVerifyAllowingDisabled('*.DISABLED_*', [
+ 'BarTest.DISABLED_TestFour',
+ 'BarTest.DISABLED_TestFive',
+ 'BazTest.DISABLED_TestC',
+ 'DISABLED_FoobarTest.DISABLED_Test2',
+ ])
+
+ self.RunAndVerify('DISABLED_*', [])
+ self.RunAndVerifyAllowingDisabled('DISABLED_*', [
+ 'DISABLED_FoobarTest.Test1',
+ 'DISABLED_FoobarTest.DISABLED_Test2',
+ 'DISABLED_FoobarbazTest.TestA',
+ ])
+
+ def testWildcardInTestCaseName(self):
+ """Tests using wildcard in the test case name."""
+
+ self.RunAndVerify('*a*.*', [
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+
+ 'BazTest.TestOne',
+ 'BazTest.TestA',
+ 'BazTest.TestB', ] + DEATH_TESTS + PARAM_TESTS)
+
+ def testWildcardInTestName(self):
+ """Tests using wildcard in the test name."""
+
+ self.RunAndVerify('*.*A*', ['FooTest.Abc', 'BazTest.TestA'])
+
+ def testFilterWithoutDot(self):
+ """Tests a filter that has no '.' in it."""
+
+ self.RunAndVerify('*z*', [
+ 'FooTest.Xyz',
+
+ 'BazTest.TestOne',
+ 'BazTest.TestA',
+ 'BazTest.TestB',
+ ])
+
+ def testTwoPatterns(self):
+ """Tests filters that consist of two patterns."""
+
+ self.RunAndVerify('Foo*.*:*A*', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BazTest.TestA',
+ ])
+
+ # An empty pattern + a non-empty one
+ self.RunAndVerify(':*A*', ['FooTest.Abc', 'BazTest.TestA'])
+
+ def testThreePatterns(self):
+ """Tests filters that consist of three patterns."""
+
+ self.RunAndVerify('*oo*:*A*:*One', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+
+ 'BazTest.TestOne',
+ 'BazTest.TestA',
+ ])
+
+ # The 2nd pattern is empty.
+ self.RunAndVerify('*oo*::*One', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+
+ 'BazTest.TestOne',
+ ])
+
+ # The last 2 patterns are empty.
+ self.RunAndVerify('*oo*::', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+ ])
+
+ def testNegativeFilters(self):
+ self.RunAndVerify('*-BazTest.TestOne', [
+ 'FooTest.Abc',
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+
+ 'BazTest.TestA',
+ 'BazTest.TestB',
+ ] + DEATH_TESTS + PARAM_TESTS)
+
+ self.RunAndVerify('*-FooTest.Abc:BazTest.*', [
+ 'FooTest.Xyz',
+
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+ ] + DEATH_TESTS + PARAM_TESTS)
+
+ self.RunAndVerify('BarTest.*-BarTest.TestOne', [
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+ ])
+
+ # Tests without leading '*'.
+ self.RunAndVerify('-FooTest.Abc:FooTest.Xyz:BazTest.*', [
+ 'BarTest.TestOne',
+ 'BarTest.TestTwo',
+ 'BarTest.TestThree',
+ ] + DEATH_TESTS + PARAM_TESTS)
+
+ # Value parameterized tests.
+ self.RunAndVerify('*/*', PARAM_TESTS)
+
+ # Value parameterized tests filtering by the sequence name.
+ self.RunAndVerify('SeqP/*', [
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestX/1',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqP/ParamTest.TestY/1',
+ ])
+
+ # Value parameterized tests filtering by the test name.
+ self.RunAndVerify('*/0', [
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqQ/ParamTest.TestX/0',
+ 'SeqQ/ParamTest.TestY/0',
+ ])
+
+ def testFlagOverridesEnvVar(self):
+ """Tests that the filter flag overrides the filtering env. variable."""
+
+ SetEnvVar(FILTER_ENV_VAR, 'Foo*')
+ args = ['--%s=%s' % (FILTER_FLAG, '*One')]
+ tests_run = RunAndExtractTestList(args)[0]
+ SetEnvVar(FILTER_ENV_VAR, None)
+
+ self.AssertSetEqual(tests_run, ['BarTest.TestOne', 'BazTest.TestOne'])
+
+ def testShardStatusFileIsCreated(self):
+ """Tests that the shard file is created if specified in the environment."""
+
+ shard_status_file = os.path.join(gtest_test_utils.GetTempDir(),
+ 'shard_status_file')
+ self.assert_(not os.path.exists(shard_status_file))
+
+ extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file}
+ try:
+ InvokeWithModifiedEnv(extra_env, RunAndReturnOutput)
+ finally:
+ self.assert_(os.path.exists(shard_status_file))
+ os.remove(shard_status_file)
+
+ def testShardStatusFileIsCreatedWithListTests(self):
+ """Tests that the shard file is created with the "list_tests" flag."""
+
+ shard_status_file = os.path.join(gtest_test_utils.GetTempDir(),
+ 'shard_status_file2')
+ self.assert_(not os.path.exists(shard_status_file))
+
+ extra_env = {SHARD_STATUS_FILE_ENV_VAR: shard_status_file}
+ try:
+ output = InvokeWithModifiedEnv(extra_env,
+ RunAndReturnOutput,
+ [LIST_TESTS_FLAG])
+ finally:
+ # This assertion ensures that Google Test enumerated the tests as
+ # opposed to running them.
+ self.assert_('[==========]' not in output,
+ 'Unexpected output during test enumeration.\n'
+ 'Please ensure that LIST_TESTS_FLAG is assigned the\n'
+ 'correct flag value for listing Google Test tests.')
+
+ self.assert_(os.path.exists(shard_status_file))
+ os.remove(shard_status_file)
+
+ if SUPPORTS_DEATH_TESTS:
+ def testShardingWorksWithDeathTests(self):
+ """Tests integration with death tests and sharding."""
+
+ gtest_filter = 'HasDeathTest.*:SeqP/*'
+ expected_tests = [
+ 'HasDeathTest.Test1',
+ 'HasDeathTest.Test2',
+
+ 'SeqP/ParamTest.TestX/0',
+ 'SeqP/ParamTest.TestX/1',
+ 'SeqP/ParamTest.TestY/0',
+ 'SeqP/ParamTest.TestY/1',
+ ]
+
+ for flag in ['--gtest_death_test_style=threadsafe',
+ '--gtest_death_test_style=fast']:
+ self.RunAndVerifyWithSharding(gtest_filter, 3, expected_tests,
+ check_exit_0=True, args=[flag])
+ self.RunAndVerifyWithSharding(gtest_filter, 5, expected_tests,
+ check_exit_0=True, args=[flag])
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_filter_unittest_.cc b/Source/ThirdParty/gtest/test/gtest_filter_unittest_.cc
new file mode 100644
index 000000000..325504fe9
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_filter_unittest_.cc
@@ -0,0 +1,140 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Unit test for Google Test test filters.
+//
+// A user can specify which test(s) in a Google Test program to run via
+// either the GTEST_FILTER environment variable or the --gtest_filter
+// flag. This is used for testing such functionality.
+//
+// The program will be invoked from a Python unit test. Don't run it
+// directly.
+
+#include <gtest/gtest.h>
+
+namespace {
+
+// Test case FooTest.
+
+class FooTest : public testing::Test {
+};
+
+TEST_F(FooTest, Abc) {
+}
+
+TEST_F(FooTest, Xyz) {
+ FAIL() << "Expected failure.";
+}
+
+// Test case BarTest.
+
+TEST(BarTest, TestOne) {
+}
+
+TEST(BarTest, TestTwo) {
+}
+
+TEST(BarTest, TestThree) {
+}
+
+TEST(BarTest, DISABLED_TestFour) {
+ FAIL() << "Expected failure.";
+}
+
+TEST(BarTest, DISABLED_TestFive) {
+ FAIL() << "Expected failure.";
+}
+
+// Test case BazTest.
+
+TEST(BazTest, TestOne) {
+ FAIL() << "Expected failure.";
+}
+
+TEST(BazTest, TestA) {
+}
+
+TEST(BazTest, TestB) {
+}
+
+TEST(BazTest, DISABLED_TestC) {
+ FAIL() << "Expected failure.";
+}
+
+// Test case HasDeathTest
+
+TEST(HasDeathTest, Test1) {
+ EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*");
+}
+
+// We need at least two death tests to make sure that the all death tests
+// aren't on the first shard.
+TEST(HasDeathTest, Test2) {
+ EXPECT_DEATH_IF_SUPPORTED(exit(1), ".*");
+}
+
+// Test case FoobarTest
+
+TEST(DISABLED_FoobarTest, Test1) {
+ FAIL() << "Expected failure.";
+}
+
+TEST(DISABLED_FoobarTest, DISABLED_Test2) {
+ FAIL() << "Expected failure.";
+}
+
+// Test case FoobarbazTest
+
+TEST(DISABLED_FoobarbazTest, TestA) {
+ FAIL() << "Expected failure.";
+}
+
+#if GTEST_HAS_PARAM_TEST
+class ParamTest : public testing::TestWithParam<int> {
+};
+
+TEST_P(ParamTest, TestX) {
+}
+
+TEST_P(ParamTest, TestY) {
+}
+
+INSTANTIATE_TEST_CASE_P(SeqP, ParamTest, testing::Values(1, 2));
+INSTANTIATE_TEST_CASE_P(SeqQ, ParamTest, testing::Values(5, 6));
+#endif // GTEST_HAS_PARAM_TEST
+
+} // namespace
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_help_test.py b/Source/ThirdParty/gtest/test/gtest_help_test.py
new file mode 100755
index 000000000..3cb4c48e0
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_help_test.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests the --help flag of Google C++ Testing Framework.
+
+SYNOPSIS
+ gtest_help_test.py --gtest_build_dir=BUILD/DIR
+ # where BUILD/DIR contains the built gtest_help_test_ file.
+ gtest_help_test.py
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import re
+import gtest_test_utils
+
+
+IS_WINDOWS = os.name == 'nt'
+
+PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_help_test_')
+FLAG_PREFIX = '--gtest_'
+CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions'
+DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style'
+UNKNOWN_FLAG = FLAG_PREFIX + 'unknown_flag_for_testing'
+LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests'
+INCORRECT_FLAG_VARIANTS = [re.sub('^--', '-', LIST_TESTS_FLAG),
+ re.sub('^--', '/', LIST_TESTS_FLAG),
+ re.sub('_', '-', LIST_TESTS_FLAG)]
+INTERNAL_FLAG_FOR_TESTING = FLAG_PREFIX + 'internal_flag_for_testing'
+
+SUPPORTS_DEATH_TESTS = "DeathTest" in gtest_test_utils.Subprocess(
+ [PROGRAM_PATH, LIST_TESTS_FLAG]).output
+
+# The help message must match this regex.
+HELP_REGEX = re.compile(
+ FLAG_PREFIX + r'list_tests.*' +
+ FLAG_PREFIX + r'filter=.*' +
+ FLAG_PREFIX + r'also_run_disabled_tests.*' +
+ FLAG_PREFIX + r'repeat=.*' +
+ FLAG_PREFIX + r'shuffle.*' +
+ FLAG_PREFIX + r'random_seed=.*' +
+ FLAG_PREFIX + r'color=.*' +
+ FLAG_PREFIX + r'print_time.*' +
+ FLAG_PREFIX + r'output=.*' +
+ FLAG_PREFIX + r'break_on_failure.*' +
+ FLAG_PREFIX + r'throw_on_failure.*',
+ re.DOTALL)
+
+
+def RunWithFlag(flag):
+ """Runs gtest_help_test_ with the given flag.
+
+ Returns:
+ the exit code and the text output as a tuple.
+ Args:
+ flag: the command-line flag to pass to gtest_help_test_, or None.
+ """
+
+ if flag is None:
+ command = [PROGRAM_PATH]
+ else:
+ command = [PROGRAM_PATH, flag]
+ child = gtest_test_utils.Subprocess(command)
+ return child.exit_code, child.output
+
+
+class GTestHelpTest(gtest_test_utils.TestCase):
+ """Tests the --help flag and its equivalent forms."""
+
+ def TestHelpFlag(self, flag):
+ """Verifies correct behavior when help flag is specified.
+
+ The right message must be printed and the tests must
+ skipped when the given flag is specified.
+
+ Args:
+ flag: A flag to pass to the binary or None.
+ """
+
+ exit_code, output = RunWithFlag(flag)
+ self.assertEquals(0, exit_code)
+ self.assert_(HELP_REGEX.search(output), output)
+ if IS_WINDOWS:
+ self.assert_(CATCH_EXCEPTIONS_FLAG in output, output)
+ else:
+ self.assert_(CATCH_EXCEPTIONS_FLAG not in output, output)
+
+ if SUPPORTS_DEATH_TESTS and not IS_WINDOWS:
+ self.assert_(DEATH_TEST_STYLE_FLAG in output, output)
+ else:
+ self.assert_(DEATH_TEST_STYLE_FLAG not in output, output)
+
+ def TestNonHelpFlag(self, flag):
+ """Verifies correct behavior when no help flag is specified.
+
+ Verifies that when no help flag is specified, the tests are run
+ and the help message is not printed.
+
+ Args:
+ flag: A flag to pass to the binary or None.
+ """
+
+ exit_code, output = RunWithFlag(flag)
+ self.assert_(exit_code != 0)
+ self.assert_(not HELP_REGEX.search(output), output)
+
+ def testPrintsHelpWithFullFlag(self):
+ self.TestHelpFlag('--help')
+
+ def testPrintsHelpWithShortFlag(self):
+ self.TestHelpFlag('-h')
+
+ def testPrintsHelpWithQuestionFlag(self):
+ self.TestHelpFlag('-?')
+
+ def testPrintsHelpWithWindowsStyleQuestionFlag(self):
+ self.TestHelpFlag('/?')
+
+ def testPrintsHelpWithUnrecognizedGoogleTestFlag(self):
+ self.TestHelpFlag(UNKNOWN_FLAG)
+
+ def testPrintsHelpWithIncorrectFlagStyle(self):
+ for incorrect_flag in INCORRECT_FLAG_VARIANTS:
+ self.TestHelpFlag(incorrect_flag)
+
+ def testRunsTestsWithoutHelpFlag(self):
+ """Verifies that when no help flag is specified, the tests are run
+ and the help message is not printed."""
+
+ self.TestNonHelpFlag(None)
+
+ def testRunsTestsWithGtestInternalFlag(self):
+ """Verifies that the tests are run and no help message is printed when
+ a flag starting with Google Test prefix and 'internal_' is supplied."""
+
+ self.TestNonHelpFlag(INTERNAL_FLAG_FOR_TESTING)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_help_test_.cc b/Source/ThirdParty/gtest/test/gtest_help_test_.cc
new file mode 100644
index 000000000..aad0d72d7
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_help_test_.cc
@@ -0,0 +1,46 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// This program is meant to be run by gtest_help_test.py. Do not run
+// it directly.
+
+#include <gtest/gtest.h>
+
+// When a help flag is specified, this program should skip the tests
+// and exit with 0; otherwise the following test will be executed,
+// causing this program to exit with a non-zero code.
+TEST(HelpFlagTest, ShouldNotBeRun) {
+ ASSERT_TRUE(false) << "Tests shouldn't be run when --help is specified.";
+}
+
+#if GTEST_HAS_DEATH_TEST
+TEST(DeathTest, UsedByPythonScriptToDetectSupportForDeathTestsInThisBinary) {}
+#endif
diff --git a/Source/ThirdParty/gtest/test/gtest_list_tests_unittest.py b/Source/ThirdParty/gtest/test/gtest_list_tests_unittest.py
new file mode 100755
index 000000000..ce8c3ef05
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_list_tests_unittest.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for Google Test's --gtest_list_tests flag.
+
+A user can ask Google Test to list all tests by specifying the
+--gtest_list_tests flag. This script tests such functionality
+by invoking gtest_list_tests_unittest_ (a program written with
+Google Test) the command line flags.
+"""
+
+__author__ = 'phanna@google.com (Patrick Hanna)'
+
+import gtest_test_utils
+
+
+# Constants.
+
+# The command line flag for enabling/disabling listing all tests.
+LIST_TESTS_FLAG = 'gtest_list_tests'
+
+# Path to the gtest_list_tests_unittest_ program.
+EXE_PATH = gtest_test_utils.GetTestExecutablePath('gtest_list_tests_unittest_')
+
+# The expected output when running gtest_list_tests_unittest_ with
+# --gtest_list_tests
+EXPECTED_OUTPUT_NO_FILTER = """FooDeathTest.
+ Test1
+Foo.
+ Bar1
+ Bar2
+ DISABLED_Bar3
+Abc.
+ Xyz
+ Def
+FooBar.
+ Baz
+FooTest.
+ Test1
+ DISABLED_Test2
+ Test3
+"""
+
+# The expected output when running gtest_list_tests_unittest_ with
+# --gtest_list_tests and --gtest_filter=Foo*.
+EXPECTED_OUTPUT_FILTER_FOO = """FooDeathTest.
+ Test1
+Foo.
+ Bar1
+ Bar2
+ DISABLED_Bar3
+FooBar.
+ Baz
+FooTest.
+ Test1
+ DISABLED_Test2
+ Test3
+"""
+
+# Utilities.
+
+
+def Run(args):
+ """Runs gtest_list_tests_unittest_ and returns the list of tests printed."""
+
+ return gtest_test_utils.Subprocess([EXE_PATH] + args,
+ capture_stderr=False).output
+
+
+# The unit test.
+
+class GTestListTestsUnitTest(gtest_test_utils.TestCase):
+ """Tests using the --gtest_list_tests flag to list all tests."""
+
+ def RunAndVerify(self, flag_value, expected_output, other_flag):
+ """Runs gtest_list_tests_unittest_ and verifies that it prints
+ the correct tests.
+
+ Args:
+ flag_value: value of the --gtest_list_tests flag;
+ None if the flag should not be present.
+
+ expected_output: the expected output after running command;
+
+ other_flag: a different flag to be passed to command
+ along with gtest_list_tests;
+ None if the flag should not be present.
+ """
+
+ if flag_value is None:
+ flag = ''
+ flag_expression = 'not set'
+ elif flag_value == '0':
+ flag = '--%s=0' % LIST_TESTS_FLAG
+ flag_expression = '0'
+ else:
+ flag = '--%s' % LIST_TESTS_FLAG
+ flag_expression = '1'
+
+ args = [flag]
+
+ if other_flag is not None:
+ args += [other_flag]
+
+ output = Run(args)
+
+ msg = ('when %s is %s, the output of "%s" is "%s".' %
+ (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output))
+
+ if expected_output is not None:
+ self.assert_(output == expected_output, msg)
+ else:
+ self.assert_(output != EXPECTED_OUTPUT_NO_FILTER, msg)
+
+ def testDefaultBehavior(self):
+ """Tests the behavior of the default mode."""
+
+ self.RunAndVerify(flag_value=None,
+ expected_output=None,
+ other_flag=None)
+
+ def testFlag(self):
+ """Tests using the --gtest_list_tests flag."""
+
+ self.RunAndVerify(flag_value='0',
+ expected_output=None,
+ other_flag=None)
+ self.RunAndVerify(flag_value='1',
+ expected_output=EXPECTED_OUTPUT_NO_FILTER,
+ other_flag=None)
+
+ def testOverrideNonFilterFlags(self):
+ """Tests that --gtest_list_tests overrides the non-filter flags."""
+
+ self.RunAndVerify(flag_value='1',
+ expected_output=EXPECTED_OUTPUT_NO_FILTER,
+ other_flag='--gtest_break_on_failure')
+
+ def testWithFilterFlags(self):
+ """Tests that --gtest_list_tests takes into account the
+ --gtest_filter flag."""
+
+ self.RunAndVerify(flag_value='1',
+ expected_output=EXPECTED_OUTPUT_FILTER_FOO,
+ other_flag='--gtest_filter=Foo*')
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_list_tests_unittest_.cc b/Source/ThirdParty/gtest/test/gtest_list_tests_unittest_.cc
new file mode 100644
index 000000000..a0ed0825b
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_list_tests_unittest_.cc
@@ -0,0 +1,85 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: phanna@google.com (Patrick Hanna)
+
+// Unit test for Google Test's --gtest_list_tests flag.
+//
+// A user can ask Google Test to list all tests that will run
+// so that when using a filter, a user will know what
+// tests to look for. The tests will not be run after listing.
+//
+// This program will be invoked from a Python unit test.
+// Don't run it directly.
+
+#include <gtest/gtest.h>
+
+namespace {
+
+// Several different test cases and tests that will be listed.
+TEST(Foo, Bar1) {
+}
+
+TEST(Foo, Bar2) {
+}
+
+TEST(Foo, DISABLED_Bar3) {
+}
+
+TEST(Abc, Xyz) {
+}
+
+TEST(Abc, Def) {
+}
+
+TEST(FooBar, Baz) {
+}
+
+class FooTest : public testing::Test {
+};
+
+TEST_F(FooTest, Test1) {
+}
+
+TEST_F(FooTest, DISABLED_Test2) {
+}
+
+TEST_F(FooTest, Test3) {
+}
+
+TEST(FooDeathTest, Test1) {
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_main_unittest.cc b/Source/ThirdParty/gtest/test/gtest_main_unittest.cc
new file mode 100644
index 000000000..7a3f0adfa
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_main_unittest.cc
@@ -0,0 +1,45 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/gtest.h>
+
+// Tests that we don't have to define main() when we link to
+// gtest_main instead of gtest.
+
+namespace {
+
+TEST(GTestMainTest, ShouldSucceed) {
+}
+
+} // namespace
+
+// We are using the main() function defined in src/gtest_main.cc, so
+// we don't define it here.
diff --git a/Source/ThirdParty/gtest/test/gtest_nc.cc b/Source/ThirdParty/gtest/test/gtest_nc.cc
new file mode 100644
index 000000000..73b5db6d4
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_nc.cc
@@ -0,0 +1,234 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// This file is the input to a negative-compilation test for Google
+// Test. Code here is NOT supposed to compile. Its purpose is to
+// verify that certain incorrect usages of the Google Test API are
+// indeed rejected by the compiler.
+//
+// We still need to write the negative-compilation test itself, which
+// will be tightly coupled with the build environment.
+//
+// TODO(wan@google.com): finish the negative-compilation test.
+
+#ifdef TEST_CANNOT_IGNORE_RUN_ALL_TESTS_RESULT
+// Tests that the result of RUN_ALL_TESTS() cannot be ignored.
+
+#include <gtest/gtest.h>
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ RUN_ALL_TESTS(); // This line shouldn't compile.
+}
+
+#elif defined(TEST_USER_CANNOT_INCLUDE_GTEST_INTERNAL_INL_H)
+// Tests that a user cannot include gtest-internal-inl.h in his code.
+
+#include "src/gtest-internal-inl.h"
+
+#elif defined(TEST_CATCHES_DECLARING_SETUP_IN_TEST_FIXTURE_WITH_TYPO)
+// Tests that the compiler catches the typo when a user declares a
+// Setup() method in a test fixture.
+
+#include <gtest/gtest.h>
+
+class MyTest : public testing::Test {
+ protected:
+ void Setup() {}
+};
+
+#elif defined(TEST_CATCHES_CALLING_SETUP_IN_TEST_WITH_TYPO)
+// Tests that the compiler catches the typo when a user calls Setup()
+// from a test fixture.
+
+#include <gtest/gtest.h>
+
+class MyTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ testing::Test::Setup(); // Tries to call SetUp() in the parent class.
+ }
+};
+
+#elif defined(TEST_CATCHES_DECLARING_SETUP_IN_ENVIRONMENT_WITH_TYPO)
+// Tests that the compiler catches the typo when a user declares a
+// Setup() method in a subclass of Environment.
+
+#include <gtest/gtest.h>
+
+class MyEnvironment : public testing::Environment {
+ public:
+ void Setup() {}
+};
+
+#elif defined(TEST_CATCHES_CALLING_SETUP_IN_ENVIRONMENT_WITH_TYPO)
+// Tests that the compiler catches the typo when a user calls Setup()
+// in an Environment.
+
+#include <gtest/gtest.h>
+
+class MyEnvironment : public testing::Environment {
+ protected:
+ virtual void SetUp() {
+ // Tries to call SetUp() in the parent class.
+ testing::Environment::Setup();
+ }
+};
+
+#elif defined(TEST_CATCHES_WRONG_CASE_IN_TYPED_TEST_P)
+// Tests that the compiler catches using the wrong test case name in
+// TYPED_TEST_P.
+
+#include <gtest/gtest.h>
+
+template <typename T>
+class FooTest : public testing::Test {
+};
+
+template <typename T>
+class BarTest : public testing::Test {
+};
+
+TYPED_TEST_CASE_P(FooTest);
+TYPED_TEST_P(BarTest, A) {} // Wrong test case name.
+REGISTER_TYPED_TEST_CASE_P(FooTest, A);
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types<int>);
+
+#elif defined(TEST_CATCHES_WRONG_CASE_IN_REGISTER_TYPED_TEST_CASE_P)
+// Tests that the compiler catches using the wrong test case name in
+// REGISTER_TYPED_TEST_CASE_P.
+
+#include <gtest/gtest.h>
+
+template <typename T>
+class FooTest : public testing::Test {
+};
+
+template <typename T>
+class BarTest : public testing::Test {
+};
+
+TYPED_TEST_CASE_P(FooTest);
+TYPED_TEST_P(FooTest, A) {}
+REGISTER_TYPED_TEST_CASE_P(BarTest, A); // Wrong test case name.
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types<int>);
+
+#elif defined(TEST_CATCHES_WRONG_CASE_IN_INSTANTIATE_TYPED_TEST_CASE_P)
+// Tests that the compiler catches using the wrong test case name in
+// INSTANTIATE_TYPED_TEST_CASE_P.
+
+#include <gtest/gtest.h>
+
+template <typename T>
+class FooTest : public testing::Test {
+};
+
+template <typename T>
+class BarTest : public testing::Test {
+};
+
+TYPED_TEST_CASE_P(FooTest);
+TYPED_TEST_P(FooTest, A) {}
+REGISTER_TYPED_TEST_CASE_P(FooTest, A);
+
+// Wrong test case name.
+INSTANTIATE_TYPED_TEST_CASE_P(My, BarTest, testing::Types<int>);
+
+#elif defined(TEST_CATCHES_INSTANTIATE_TYPED_TESET_CASE_P_WITH_SAME_NAME_PREFIX)
+// Tests that the compiler catches instantiating TYPED_TEST_CASE_P
+// twice with the same name prefix.
+
+#include <gtest/gtest.h>
+
+template <typename T>
+class FooTest : public testing::Test {
+};
+
+TYPED_TEST_CASE_P(FooTest);
+TYPED_TEST_P(FooTest, A) {}
+REGISTER_TYPED_TEST_CASE_P(FooTest, A);
+
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types<int>);
+
+// Wrong name prefix: "My" has been used.
+INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, testing::Types<double>);
+
+#elif defined(TEST_STATIC_ASSERT_TYPE_EQ_IS_NOT_A_TYPE)
+
+#include <gtest/gtest.h>
+
+// Tests that StaticAssertTypeEq<T1, T2> cannot be used as a type.
+testing::StaticAssertTypeEq<int, int> dummy;
+
+#elif defined(TEST_STATIC_ASSERT_TYPE_EQ_WORKS_IN_NAMESPACE)
+
+#include <gtest/gtest.h>
+
+// Tests that StaticAssertTypeEq<T1, T2> works in a namespace scope.
+static bool dummy = testing::StaticAssertTypeEq<int, const int>();
+
+#elif defined(TEST_STATIC_ASSERT_TYPE_EQ_WORKS_IN_CLASS)
+
+#include <gtest/gtest.h>
+
+template <typename T>
+class Helper {
+ public:
+ // Tests that StaticAssertTypeEq<T1, T2> works in a class.
+ Helper() { testing::StaticAssertTypeEq<int, T>(); }
+
+ void DoSomething() {}
+};
+
+void Test() {
+ Helper<bool> h;
+ h.DoSomething(); // To avoid the "unused variable" warning.
+}
+
+#elif defined(TEST_STATIC_ASSERT_TYPE_EQ_WORKS_IN_FUNCTION)
+
+#include <gtest/gtest.h>
+
+void Test() {
+ // Tests that StaticAssertTypeEq<T1, T2> works inside a function.
+ testing::StaticAssertTypeEq<const int, int>();
+}
+
+#else
+// A sanity test. This should compile.
+
+#include <gtest/gtest.h>
+
+int main() {
+ return RUN_ALL_TESTS();
+}
+
+#endif
diff --git a/Source/ThirdParty/gtest/test/gtest_nc_test.py b/Source/ThirdParty/gtest/test/gtest_nc_test.py
new file mode 100755
index 000000000..06ffb3f80
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_nc_test.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+#
+# Copyright 2007, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Negative compilation test for Google Test."""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import sys
+import unittest
+
+
+IS_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux'
+if not IS_LINUX:
+ sys.exit(0) # Negative compilation tests are not supported on Windows & Mac.
+
+
+class GTestNCTest(unittest.TestCase):
+ """Negative compilation test for Google Test."""
+
+ def testCompilerError(self):
+ """Verifies that erroneous code leads to expected compiler
+ messages."""
+
+ # Defines a list of test specs, where each element is a tuple
+ # (test name, list of regexes for matching the compiler errors).
+ test_specs = [
+ ('CANNOT_IGNORE_RUN_ALL_TESTS_RESULT',
+ [r'ignoring return value']),
+
+ ('USER_CANNOT_INCLUDE_GTEST_INTERNAL_INL_H',
+ [r'must not be included except by Google Test itself']),
+
+ ('CATCHES_DECLARING_SETUP_IN_TEST_FIXTURE_WITH_TYPO',
+ [r'Setup_should_be_spelled_SetUp']),
+
+ ('CATCHES_CALLING_SETUP_IN_TEST_WITH_TYPO',
+ [r'Setup_should_be_spelled_SetUp']),
+
+ ('CATCHES_DECLARING_SETUP_IN_ENVIRONMENT_WITH_TYPO',
+ [r'Setup_should_be_spelled_SetUp']),
+
+ ('CATCHES_CALLING_SETUP_IN_ENVIRONMENT_WITH_TYPO',
+ [r'Setup_should_be_spelled_SetUp']),
+
+ ('CATCHES_WRONG_CASE_IN_TYPED_TEST_P',
+ [r'BarTest.*was not declared']),
+
+ ('CATCHES_WRONG_CASE_IN_REGISTER_TYPED_TEST_CASE_P',
+ [r'BarTest.*was not declared']),
+
+ ('CATCHES_WRONG_CASE_IN_INSTANTIATE_TYPED_TEST_CASE_P',
+ [r'BarTest.*not declared']),
+
+ ('CATCHES_INSTANTIATE_TYPED_TESET_CASE_P_WITH_SAME_NAME_PREFIX',
+ [r'redefinition of.*My.*FooTest']),
+
+ ('STATIC_ASSERT_TYPE_EQ_IS_NOT_A_TYPE',
+ [r'StaticAssertTypeEq.* does not name a type']),
+
+ ('STATIC_ASSERT_TYPE_EQ_WORKS_IN_NAMESPACE',
+ [r'StaticAssertTypeEq.*int.*const int']),
+
+ ('STATIC_ASSERT_TYPE_EQ_WORKS_IN_CLASS',
+ [r'StaticAssertTypeEq.*int.*bool']),
+
+ ('STATIC_ASSERT_TYPE_EQ_WORKS_IN_FUNCTION',
+ [r'StaticAssertTypeEq.*const int.*int']),
+
+ ('SANITY',
+ None)
+ ]
+
+ # TODO(wan@google.com): verify that the test specs are satisfied.
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Source/ThirdParty/gtest/test/gtest_no_test_unittest.cc b/Source/ThirdParty/gtest/test/gtest_no_test_unittest.cc
new file mode 100644
index 000000000..afe2dc0c9
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_no_test_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests that a Google Test program that has no test defined can run
+// successfully.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/gtest.h>
+
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+
+ // An ad-hoc assertion outside of all tests.
+ //
+ // This serves two purposes:
+ //
+ // 1. It verifies that an ad-hoc assertion can be executed even if
+ // no test is defined.
+ // 2. We had a bug where the XML output won't be generated if an
+ // assertion is executed before RUN_ALL_TESTS() is called, even
+ // though --gtest_output=xml is specified. This makes sure the
+ // bug is fixed and doesn't regress.
+ EXPECT_EQ(1, 1);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_output_test.py b/Source/ThirdParty/gtest/test/gtest_output_test.py
new file mode 100755
index 000000000..192030a20
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_output_test.py
@@ -0,0 +1,327 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests the text output of Google C++ Testing Framework.
+
+SYNOPSIS
+ gtest_output_test.py --gtest_build_dir=BUILD/DIR --gengolden
+ # where BUILD/DIR contains the built gtest_output_test_ file.
+ gtest_output_test.py --gengolden
+ gtest_output_test.py
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import re
+import sys
+import gtest_test_utils
+
+
+# The flag for generating the golden file
+GENGOLDEN_FLAG = '--gengolden'
+CATCH_EXCEPTIONS_ENV_VAR_NAME = 'GTEST_CATCH_EXCEPTIONS'
+
+IS_WINDOWS = os.name == 'nt'
+
+if IS_WINDOWS:
+ GOLDEN_NAME = 'gtest_output_test_golden_win.txt'
+else:
+ GOLDEN_NAME = 'gtest_output_test_golden_lin.txt'
+
+PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_output_test_')
+
+# At least one command we exercise must not have the
+# --gtest_internal_skip_environment_and_ad_hoc_tests flag.
+COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests'])
+COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes'])
+COMMAND_WITH_TIME = ({}, [PROGRAM_PATH,
+ '--gtest_print_time',
+ '--gtest_internal_skip_environment_and_ad_hoc_tests',
+ '--gtest_filter=FatalFailureTest.*:LoggingTest.*'])
+COMMAND_WITH_DISABLED = (
+ {}, [PROGRAM_PATH,
+ '--gtest_also_run_disabled_tests',
+ '--gtest_internal_skip_environment_and_ad_hoc_tests',
+ '--gtest_filter=*DISABLED_*'])
+COMMAND_WITH_SHARDING = (
+ {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'},
+ [PROGRAM_PATH,
+ '--gtest_internal_skip_environment_and_ad_hoc_tests',
+ '--gtest_filter=PassingTest.*'])
+
+GOLDEN_PATH = os.path.join(gtest_test_utils.GetSourceDir(), GOLDEN_NAME)
+
+
+def ToUnixLineEnding(s):
+ """Changes all Windows/Mac line endings in s to UNIX line endings."""
+
+ return s.replace('\r\n', '\n').replace('\r', '\n')
+
+
+def RemoveLocations(test_output):
+ """Removes all file location info from a Google Test program's output.
+
+ Args:
+ test_output: the output of a Google Test program.
+
+ Returns:
+ output with all file location info (in the form of
+ 'DIRECTORY/FILE_NAME:LINE_NUMBER: 'or
+ 'DIRECTORY\\FILE_NAME(LINE_NUMBER): ') replaced by
+ 'FILE_NAME:#: '.
+ """
+
+ return re.sub(r'.*[/\\](.+)(\:\d+|\(\d+\))\: ', r'\1:#: ', test_output)
+
+
+def RemoveStackTraceDetails(output):
+ """Removes all stack traces from a Google Test program's output."""
+
+ # *? means "find the shortest string that matches".
+ return re.sub(r'Stack trace:(.|\n)*?\n\n',
+ 'Stack trace: (omitted)\n\n', output)
+
+
+def RemoveStackTraces(output):
+ """Removes all traces of stack traces from a Google Test program's output."""
+
+ # *? means "find the shortest string that matches".
+ return re.sub(r'Stack trace:(.|\n)*?\n\n', '', output)
+
+
+def RemoveTime(output):
+ """Removes all time information from a Google Test program's output."""
+
+ return re.sub(r'\(\d+ ms', '(? ms', output)
+
+
+def RemoveTypeInfoDetails(test_output):
+ """Removes compiler-specific type info from Google Test program's output.
+
+ Args:
+ test_output: the output of a Google Test program.
+
+ Returns:
+ output with type information normalized to canonical form.
+ """
+
+ # some compilers output the name of type 'unsigned int' as 'unsigned'
+ return re.sub(r'unsigned int', 'unsigned', test_output)
+
+
+def RemoveTestCounts(output):
+ """Removes test counts from a Google Test program's output."""
+
+ output = re.sub(r'\d+ tests?, listed below',
+ '? tests, listed below', output)
+ output = re.sub(r'\d+ FAILED TESTS',
+ '? FAILED TESTS', output)
+ output = re.sub(r'\d+ tests? from \d+ test cases?',
+ '? tests from ? test cases', output)
+ output = re.sub(r'\d+ tests? from ([a-zA-Z_])',
+ r'? tests from \1', output)
+ return re.sub(r'\d+ tests?\.', '? tests.', output)
+
+
+def RemoveMatchingTests(test_output, pattern):
+ """Removes output of specified tests from a Google Test program's output.
+
+ This function strips not only the beginning and the end of a test but also
+ all output in between.
+
+ Args:
+ test_output: A string containing the test output.
+ pattern: A regex string that matches names of test cases or
+ tests to remove.
+
+ Returns:
+ Contents of test_output with tests whose names match pattern removed.
+ """
+
+ test_output = re.sub(
+ r'.*\[ RUN \] .*%s(.|\n)*?\[( FAILED | OK )\] .*%s.*\n' % (
+ pattern, pattern),
+ '',
+ test_output)
+ return re.sub(r'.*%s.*\n' % pattern, '', test_output)
+
+
+def NormalizeOutput(output):
+ """Normalizes output (the output of gtest_output_test_.exe)."""
+
+ output = ToUnixLineEnding(output)
+ output = RemoveLocations(output)
+ output = RemoveStackTraceDetails(output)
+ output = RemoveTime(output)
+ return output
+
+
+def GetShellCommandOutput(env_cmd):
+ """Runs a command in a sub-process, and returns its output in a string.
+
+ Args:
+ env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra
+ environment variables to set, and element 1 is a string with
+ the command and any flags.
+
+ Returns:
+ A string with the command's combined standard and diagnostic output.
+ """
+
+ # Spawns cmd in a sub-process, and gets its standard I/O file objects.
+ # Set and save the environment properly.
+ environ = os.environ.copy()
+ environ.update(env_cmd[0])
+ p = gtest_test_utils.Subprocess(env_cmd[1], env=environ)
+
+ return p.output
+
+
+def GetCommandOutput(env_cmd):
+ """Runs a command and returns its output with all file location
+ info stripped off.
+
+ Args:
+ env_cmd: The shell command. A 2-tuple where element 0 is a dict of extra
+ environment variables to set, and element 1 is a string with
+ the command and any flags.
+ """
+
+ # Disables exception pop-ups on Windows.
+ environ, cmdline = env_cmd
+ environ = dict(environ) # Ensures we are modifying a copy.
+ environ[CATCH_EXCEPTIONS_ENV_VAR_NAME] = '1'
+ return NormalizeOutput(GetShellCommandOutput((environ, cmdline)))
+
+
+def GetOutputOfAllCommands():
+ """Returns concatenated output from several representative commands."""
+
+ return (GetCommandOutput(COMMAND_WITH_COLOR) +
+ GetCommandOutput(COMMAND_WITH_TIME) +
+ GetCommandOutput(COMMAND_WITH_DISABLED) +
+ GetCommandOutput(COMMAND_WITH_SHARDING))
+
+
+test_list = GetShellCommandOutput(COMMAND_LIST_TESTS)
+SUPPORTS_DEATH_TESTS = 'DeathTest' in test_list
+SUPPORTS_TYPED_TESTS = 'TypedTest' in test_list
+SUPPORTS_THREADS = 'ExpectFailureWithThreadsTest' in test_list
+SUPPORTS_STACK_TRACES = False
+
+CAN_GENERATE_GOLDEN_FILE = (SUPPORTS_DEATH_TESTS and
+ SUPPORTS_TYPED_TESTS and
+ SUPPORTS_THREADS)
+
+
+class GTestOutputTest(gtest_test_utils.TestCase):
+ def RemoveUnsupportedTests(self, test_output):
+ if not SUPPORTS_DEATH_TESTS:
+ test_output = RemoveMatchingTests(test_output, 'DeathTest')
+ if not SUPPORTS_TYPED_TESTS:
+ test_output = RemoveMatchingTests(test_output, 'TypedTest')
+ test_output = RemoveMatchingTests(test_output, 'TypedDeathTest')
+ test_output = RemoveMatchingTests(test_output, 'TypeParamDeathTest')
+ if not SUPPORTS_THREADS:
+ test_output = RemoveMatchingTests(test_output,
+ 'ExpectFailureWithThreadsTest')
+ test_output = RemoveMatchingTests(test_output,
+ 'ScopedFakeTestPartResultReporterTest')
+ test_output = RemoveMatchingTests(test_output,
+ 'WorksConcurrently')
+ if not SUPPORTS_STACK_TRACES:
+ test_output = RemoveStackTraces(test_output)
+
+ return test_output
+
+ def testOutput(self):
+ output = GetOutputOfAllCommands()
+
+ golden_file = open(GOLDEN_PATH, 'rb')
+ # A mis-configured source control system can cause \r appear in EOL
+ # sequences when we read the golden file irrespective of an operating
+ # system used. Therefore, we need to strip those \r's from newlines
+ # unconditionally.
+ golden = ToUnixLineEnding(golden_file.read())
+ golden_file.close()
+
+ # We want the test to pass regardless of certain features being
+ # supported or not.
+
+ # We still have to remove type name specifics in all cases.
+ normalized_actual = RemoveTypeInfoDetails(output)
+ normalized_golden = RemoveTypeInfoDetails(golden)
+
+ if CAN_GENERATE_GOLDEN_FILE:
+ self.assertEqual(normalized_golden, normalized_actual)
+ else:
+ normalized_actual = RemoveTestCounts(normalized_actual)
+ normalized_golden = RemoveTestCounts(self.RemoveUnsupportedTests(
+ normalized_golden))
+
+ # This code is very handy when debugging golden file differences:
+ if os.getenv('DEBUG_GTEST_OUTPUT_TEST'):
+ open(os.path.join(
+ gtest_test_utils.GetSourceDir(),
+ '_gtest_output_test_normalized_actual.txt'), 'wb').write(
+ normalized_actual)
+ open(os.path.join(
+ gtest_test_utils.GetSourceDir(),
+ '_gtest_output_test_normalized_golden.txt'), 'wb').write(
+ normalized_golden)
+
+ self.assertEqual(normalized_golden, normalized_actual)
+
+
+if __name__ == '__main__':
+ if sys.argv[1:] == [GENGOLDEN_FLAG]:
+ if CAN_GENERATE_GOLDEN_FILE:
+ output = GetOutputOfAllCommands()
+ golden_file = open(GOLDEN_PATH, 'wb')
+ golden_file.write(output)
+ golden_file.close()
+ else:
+ message = (
+ """Unable to write a golden file when compiled in an environment
+that does not support all the required features (death tests""")
+ if IS_WINDOWS:
+ message += (
+ """\nand typed tests). Please check that you are using VC++ 8.0 SP1
+or higher as your compiler.""")
+ else:
+ message += """\ntyped tests, and threads). Please generate the
+golden file using a binary built with those features enabled."""
+
+ sys.stderr.write(message)
+ sys.exit(1)
+ else:
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_output_test_.cc b/Source/ThirdParty/gtest/test/gtest_output_test_.cc
new file mode 100644
index 000000000..273e8e93e
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_output_test_.cc
@@ -0,0 +1,1135 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// A unit test for Google Test itself. This verifies that the basic
+// constructs of Google Test work.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/gtest-spi.h>
+#include <gtest/gtest.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#include <stdlib.h>
+
+#if GTEST_IS_THREADSAFE
+using testing::ScopedFakeTestPartResultReporter;
+using testing::TestPartResultArray;
+
+using testing::internal::Notification;
+using testing::internal::ThreadWithParam;
+#endif
+
+namespace posix = ::testing::internal::posix;
+using testing::internal::String;
+using testing::internal::scoped_ptr;
+
+// Tests catching fatal failures.
+
+// A subroutine used by the following test.
+void TestEq1(int x) {
+ ASSERT_EQ(1, x);
+}
+
+// This function calls a test subroutine, catches the fatal failure it
+// generates, and then returns early.
+void TryTestSubroutine() {
+ // Calls a subrountine that yields a fatal failure.
+ TestEq1(2);
+
+ // Catches the fatal failure and aborts the test.
+ //
+ // The testing::Test:: prefix is necessary when calling
+ // HasFatalFailure() outside of a TEST, TEST_F, or test fixture.
+ if (testing::Test::HasFatalFailure()) return;
+
+ // If we get here, something is wrong.
+ FAIL() << "This should never be reached.";
+}
+
+TEST(PassingTest, PassingTest1) {
+}
+
+TEST(PassingTest, PassingTest2) {
+}
+
+// Tests catching a fatal failure in a subroutine.
+TEST(FatalFailureTest, FatalFailureInSubroutine) {
+ printf("(expecting a failure that x should be 1)\n");
+
+ TryTestSubroutine();
+}
+
+// Tests catching a fatal failure in a nested subroutine.
+TEST(FatalFailureTest, FatalFailureInNestedSubroutine) {
+ printf("(expecting a failure that x should be 1)\n");
+
+ // Calls a subrountine that yields a fatal failure.
+ TryTestSubroutine();
+
+ // Catches the fatal failure and aborts the test.
+ //
+ // When calling HasFatalFailure() inside a TEST, TEST_F, or test
+ // fixture, the testing::Test:: prefix is not needed.
+ if (HasFatalFailure()) return;
+
+ // If we get here, something is wrong.
+ FAIL() << "This should never be reached.";
+}
+
+// Tests HasFatalFailure() after a failed EXPECT check.
+TEST(FatalFailureTest, NonfatalFailureInSubroutine) {
+ printf("(expecting a failure on false)\n");
+ EXPECT_TRUE(false); // Generates a nonfatal failure
+ ASSERT_FALSE(HasFatalFailure()); // This should succeed.
+}
+
+// Tests interleaving user logging and Google Test assertions.
+TEST(LoggingTest, InterleavingLoggingAndAssertions) {
+ static const int a[4] = {
+ 3, 9, 2, 6
+ };
+
+ printf("(expecting 2 failures on (3) >= (a[i]))\n");
+ for (int i = 0; i < static_cast<int>(sizeof(a)/sizeof(*a)); i++) {
+ printf("i == %d\n", i);
+ EXPECT_GE(3, a[i]);
+ }
+}
+
+// Tests the SCOPED_TRACE macro.
+
+// A helper function for testing SCOPED_TRACE.
+void SubWithoutTrace(int n) {
+ EXPECT_EQ(1, n);
+ ASSERT_EQ(2, n);
+}
+
+// Another helper function for testing SCOPED_TRACE.
+void SubWithTrace(int n) {
+ SCOPED_TRACE(testing::Message() << "n = " << n);
+
+ SubWithoutTrace(n);
+}
+
+// Tests that SCOPED_TRACE() obeys lexical scopes.
+TEST(SCOPED_TRACETest, ObeysScopes) {
+ printf("(expected to fail)\n");
+
+ // There should be no trace before SCOPED_TRACE() is invoked.
+ ADD_FAILURE() << "This failure is expected, and shouldn't have a trace.";
+
+ {
+ SCOPED_TRACE("Expected trace");
+ // After SCOPED_TRACE(), a failure in the current scope should contain
+ // the trace.
+ ADD_FAILURE() << "This failure is expected, and should have a trace.";
+ }
+
+ // Once the control leaves the scope of the SCOPED_TRACE(), there
+ // should be no trace again.
+ ADD_FAILURE() << "This failure is expected, and shouldn't have a trace.";
+}
+
+// Tests that SCOPED_TRACE works inside a loop.
+TEST(SCOPED_TRACETest, WorksInLoop) {
+ printf("(expected to fail)\n");
+
+ for (int i = 1; i <= 2; i++) {
+ SCOPED_TRACE(testing::Message() << "i = " << i);
+
+ SubWithoutTrace(i);
+ }
+}
+
+// Tests that SCOPED_TRACE works in a subroutine.
+TEST(SCOPED_TRACETest, WorksInSubroutine) {
+ printf("(expected to fail)\n");
+
+ SubWithTrace(1);
+ SubWithTrace(2);
+}
+
+// Tests that SCOPED_TRACE can be nested.
+TEST(SCOPED_TRACETest, CanBeNested) {
+ printf("(expected to fail)\n");
+
+ SCOPED_TRACE(""); // A trace without a message.
+
+ SubWithTrace(2);
+}
+
+// Tests that multiple SCOPED_TRACEs can be used in the same scope.
+TEST(SCOPED_TRACETest, CanBeRepeated) {
+ printf("(expected to fail)\n");
+
+ SCOPED_TRACE("A");
+ ADD_FAILURE()
+ << "This failure is expected, and should contain trace point A.";
+
+ SCOPED_TRACE("B");
+ ADD_FAILURE()
+ << "This failure is expected, and should contain trace point A and B.";
+
+ {
+ SCOPED_TRACE("C");
+ ADD_FAILURE() << "This failure is expected, and should contain "
+ << "trace point A, B, and C.";
+ }
+
+ SCOPED_TRACE("D");
+ ADD_FAILURE() << "This failure is expected, and should contain "
+ << "trace point A, B, and D.";
+}
+
+#if GTEST_IS_THREADSAFE
+// Tests that SCOPED_TRACE()s can be used concurrently from multiple
+// threads. Namely, an assertion should be affected by
+// SCOPED_TRACE()s in its own thread only.
+
+// Here's the sequence of actions that happen in the test:
+//
+// Thread A (main) | Thread B (spawned)
+// ===============================|================================
+// spawns thread B |
+// -------------------------------+--------------------------------
+// waits for n1 | SCOPED_TRACE("Trace B");
+// | generates failure #1
+// | notifies n1
+// -------------------------------+--------------------------------
+// SCOPED_TRACE("Trace A"); | waits for n2
+// generates failure #2 |
+// notifies n2 |
+// -------------------------------|--------------------------------
+// waits for n3 | generates failure #3
+// | trace B dies
+// | generates failure #4
+// | notifies n3
+// -------------------------------|--------------------------------
+// generates failure #5 | finishes
+// trace A dies |
+// generates failure #6 |
+// -------------------------------|--------------------------------
+// waits for thread B to finish |
+
+struct CheckPoints {
+ Notification n1;
+ Notification n2;
+ Notification n3;
+};
+
+static void ThreadWithScopedTrace(CheckPoints* check_points) {
+ {
+ SCOPED_TRACE("Trace B");
+ ADD_FAILURE()
+ << "Expected failure #1 (in thread B, only trace B alive).";
+ check_points->n1.Notify();
+ check_points->n2.WaitForNotification();
+
+ ADD_FAILURE()
+ << "Expected failure #3 (in thread B, trace A & B both alive).";
+ } // Trace B dies here.
+ ADD_FAILURE()
+ << "Expected failure #4 (in thread B, only trace A alive).";
+ check_points->n3.Notify();
+}
+
+TEST(SCOPED_TRACETest, WorksConcurrently) {
+ printf("(expecting 6 failures)\n");
+
+ CheckPoints check_points;
+ ThreadWithParam<CheckPoints*> thread(&ThreadWithScopedTrace,
+ &check_points,
+ NULL);
+ check_points.n1.WaitForNotification();
+
+ {
+ SCOPED_TRACE("Trace A");
+ ADD_FAILURE()
+ << "Expected failure #2 (in thread A, trace A & B both alive).";
+ check_points.n2.Notify();
+ check_points.n3.WaitForNotification();
+
+ ADD_FAILURE()
+ << "Expected failure #5 (in thread A, only trace A alive).";
+ } // Trace A dies here.
+ ADD_FAILURE()
+ << "Expected failure #6 (in thread A, no trace alive).";
+ thread.Join();
+}
+#endif // GTEST_IS_THREADSAFE
+
+TEST(DisabledTestsWarningTest,
+ DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning) {
+ // This test body is intentionally empty. Its sole purpose is for
+ // verifying that the --gtest_also_run_disabled_tests flag
+ // suppresses the "YOU HAVE 12 DISABLED TESTS" warning at the end of
+ // the test output.
+}
+
+// Tests using assertions outside of TEST and TEST_F.
+//
+// This function creates two failures intentionally.
+void AdHocTest() {
+ printf("The non-test part of the code is expected to have 2 failures.\n\n");
+ EXPECT_TRUE(false);
+ EXPECT_EQ(2, 3);
+}
+
+// Runs all TESTs, all TEST_Fs, and the ad hoc test.
+int RunAllTests() {
+ AdHocTest();
+ return RUN_ALL_TESTS();
+}
+
+// Tests non-fatal failures in the fixture constructor.
+class NonFatalFailureInFixtureConstructorTest : public testing::Test {
+ protected:
+ NonFatalFailureInFixtureConstructorTest() {
+ printf("(expecting 5 failures)\n");
+ ADD_FAILURE() << "Expected failure #1, in the test fixture c'tor.";
+ }
+
+ ~NonFatalFailureInFixtureConstructorTest() {
+ ADD_FAILURE() << "Expected failure #5, in the test fixture d'tor.";
+ }
+
+ virtual void SetUp() {
+ ADD_FAILURE() << "Expected failure #2, in SetUp().";
+ }
+
+ virtual void TearDown() {
+ ADD_FAILURE() << "Expected failure #4, in TearDown.";
+ }
+};
+
+TEST_F(NonFatalFailureInFixtureConstructorTest, FailureInConstructor) {
+ ADD_FAILURE() << "Expected failure #3, in the test body.";
+}
+
+// Tests fatal failures in the fixture constructor.
+class FatalFailureInFixtureConstructorTest : public testing::Test {
+ protected:
+ FatalFailureInFixtureConstructorTest() {
+ printf("(expecting 2 failures)\n");
+ Init();
+ }
+
+ ~FatalFailureInFixtureConstructorTest() {
+ ADD_FAILURE() << "Expected failure #2, in the test fixture d'tor.";
+ }
+
+ virtual void SetUp() {
+ ADD_FAILURE() << "UNEXPECTED failure in SetUp(). "
+ << "We should never get here, as the test fixture c'tor "
+ << "had a fatal failure.";
+ }
+
+ virtual void TearDown() {
+ ADD_FAILURE() << "UNEXPECTED failure in TearDown(). "
+ << "We should never get here, as the test fixture c'tor "
+ << "had a fatal failure.";
+ }
+ private:
+ void Init() {
+ FAIL() << "Expected failure #1, in the test fixture c'tor.";
+ }
+};
+
+TEST_F(FatalFailureInFixtureConstructorTest, FailureInConstructor) {
+ ADD_FAILURE() << "UNEXPECTED failure in the test body. "
+ << "We should never get here, as the test fixture c'tor "
+ << "had a fatal failure.";
+}
+
+// Tests non-fatal failures in SetUp().
+class NonFatalFailureInSetUpTest : public testing::Test {
+ protected:
+ virtual ~NonFatalFailureInSetUpTest() {
+ Deinit();
+ }
+
+ virtual void SetUp() {
+ printf("(expecting 4 failures)\n");
+ ADD_FAILURE() << "Expected failure #1, in SetUp().";
+ }
+
+ virtual void TearDown() {
+ FAIL() << "Expected failure #3, in TearDown().";
+ }
+ private:
+ void Deinit() {
+ FAIL() << "Expected failure #4, in the test fixture d'tor.";
+ }
+};
+
+TEST_F(NonFatalFailureInSetUpTest, FailureInSetUp) {
+ FAIL() << "Expected failure #2, in the test function.";
+}
+
+// Tests fatal failures in SetUp().
+class FatalFailureInSetUpTest : public testing::Test {
+ protected:
+ virtual ~FatalFailureInSetUpTest() {
+ Deinit();
+ }
+
+ virtual void SetUp() {
+ printf("(expecting 3 failures)\n");
+ FAIL() << "Expected failure #1, in SetUp().";
+ }
+
+ virtual void TearDown() {
+ FAIL() << "Expected failure #2, in TearDown().";
+ }
+ private:
+ void Deinit() {
+ FAIL() << "Expected failure #3, in the test fixture d'tor.";
+ }
+};
+
+TEST_F(FatalFailureInSetUpTest, FailureInSetUp) {
+ FAIL() << "UNEXPECTED failure in the test function. "
+ << "We should never get here, as SetUp() failed.";
+}
+
+#if GTEST_OS_WINDOWS
+
+// This group of tests verifies that Google Test handles SEH and C++
+// exceptions correctly.
+
+// A function that throws an SEH exception.
+static void ThrowSEH() {
+ int* p = NULL;
+ *p = 0; // Raises an access violation.
+}
+
+// Tests exceptions thrown in the test fixture constructor.
+class ExceptionInFixtureCtorTest : public testing::Test {
+ protected:
+ ExceptionInFixtureCtorTest() {
+ printf("(expecting a failure on thrown exception "
+ "in the test fixture's constructor)\n");
+
+ ThrowSEH();
+ }
+
+ virtual ~ExceptionInFixtureCtorTest() {
+ Deinit();
+ }
+
+ virtual void SetUp() {
+ FAIL() << "UNEXPECTED failure in SetUp(). "
+ << "We should never get here, as the test fixture c'tor threw.";
+ }
+
+ virtual void TearDown() {
+ FAIL() << "UNEXPECTED failure in TearDown(). "
+ << "We should never get here, as the test fixture c'tor threw.";
+ }
+ private:
+ void Deinit() {
+ FAIL() << "UNEXPECTED failure in the d'tor. "
+ << "We should never get here, as the test fixture c'tor threw.";
+ }
+};
+
+TEST_F(ExceptionInFixtureCtorTest, ExceptionInFixtureCtor) {
+ FAIL() << "UNEXPECTED failure in the test function. "
+ << "We should never get here, as the test fixture c'tor threw.";
+}
+
+// Tests exceptions thrown in SetUp().
+class ExceptionInSetUpTest : public testing::Test {
+ protected:
+ virtual ~ExceptionInSetUpTest() {
+ Deinit();
+ }
+
+ virtual void SetUp() {
+ printf("(expecting 3 failures)\n");
+
+ ThrowSEH();
+ }
+
+ virtual void TearDown() {
+ FAIL() << "Expected failure #2, in TearDown().";
+ }
+ private:
+ void Deinit() {
+ FAIL() << "Expected failure #3, in the test fixture d'tor.";
+ }
+};
+
+TEST_F(ExceptionInSetUpTest, ExceptionInSetUp) {
+ FAIL() << "UNEXPECTED failure in the test function. "
+ << "We should never get here, as SetUp() threw.";
+}
+
+// Tests that TearDown() and the test fixture d'tor are always called,
+// even when the test function throws an exception.
+class ExceptionInTestFunctionTest : public testing::Test {
+ protected:
+ virtual ~ExceptionInTestFunctionTest() {
+ Deinit();
+ }
+
+ virtual void TearDown() {
+ FAIL() << "Expected failure #2, in TearDown().";
+ }
+ private:
+ void Deinit() {
+ FAIL() << "Expected failure #3, in the test fixture d'tor.";
+ }
+};
+
+// Tests that the test fixture d'tor is always called, even when the
+// test function throws an SEH exception.
+TEST_F(ExceptionInTestFunctionTest, SEH) {
+ printf("(expecting 3 failures)\n");
+
+ ThrowSEH();
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Tests that the test fixture d'tor is always called, even when the
+// test function throws a C++ exception. We do this only when
+// GTEST_HAS_EXCEPTIONS is non-zero, i.e. C++ exceptions are enabled.
+TEST_F(ExceptionInTestFunctionTest, CppException) {
+ throw 1;
+}
+
+// Tests exceptions thrown in TearDown().
+class ExceptionInTearDownTest : public testing::Test {
+ protected:
+ virtual ~ExceptionInTearDownTest() {
+ Deinit();
+ }
+
+ virtual void TearDown() {
+ throw 1;
+ }
+ private:
+ void Deinit() {
+ FAIL() << "Expected failure #2, in the test fixture d'tor.";
+ }
+};
+
+TEST_F(ExceptionInTearDownTest, ExceptionInTearDown) {
+ printf("(expecting 2 failures)\n");
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+#endif // GTEST_OS_WINDOWS
+
+#if GTEST_IS_THREADSAFE
+
+// A unary function that may die.
+void DieIf(bool should_die) {
+ GTEST_CHECK_(!should_die) << " - death inside DieIf().";
+}
+
+// Tests running death tests in a multi-threaded context.
+
+// Used for coordination between the main and the spawn thread.
+struct SpawnThreadNotifications {
+ SpawnThreadNotifications() {}
+
+ Notification spawn_thread_started;
+ Notification spawn_thread_ok_to_terminate;
+
+ private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SpawnThreadNotifications);
+};
+
+// The function to be executed in the thread spawn by the
+// MultipleThreads test (below).
+static void ThreadRoutine(SpawnThreadNotifications* notifications) {
+ // Signals the main thread that this thread has started.
+ notifications->spawn_thread_started.Notify();
+
+ // Waits for permission to finish from the main thread.
+ notifications->spawn_thread_ok_to_terminate.WaitForNotification();
+}
+
+// This is a death-test test, but it's not named with a DeathTest
+// suffix. It starts threads which might interfere with later
+// death tests, so it must run after all other death tests.
+class DeathTestAndMultiThreadsTest : public testing::Test {
+ protected:
+ // Starts a thread and waits for it to begin.
+ virtual void SetUp() {
+ thread_.reset(new ThreadWithParam<SpawnThreadNotifications*>(
+ &ThreadRoutine, &notifications_, NULL));
+ notifications_.spawn_thread_started.WaitForNotification();
+ }
+ // Tells the thread to finish, and reaps it.
+ // Depending on the version of the thread library in use,
+ // a manager thread might still be left running that will interfere
+ // with later death tests. This is unfortunate, but this class
+ // cleans up after itself as best it can.
+ virtual void TearDown() {
+ notifications_.spawn_thread_ok_to_terminate.Notify();
+ }
+
+ private:
+ SpawnThreadNotifications notifications_;
+ scoped_ptr<ThreadWithParam<SpawnThreadNotifications*> > thread_;
+};
+
+#endif // GTEST_IS_THREADSAFE
+
+// The MixedUpTestCaseTest test case verifies that Google Test will fail a
+// test if it uses a different fixture class than what other tests in
+// the same test case use. It deliberately contains two fixture
+// classes with the same name but defined in different namespaces.
+
+// The MixedUpTestCaseWithSameTestNameTest test case verifies that
+// when the user defines two tests with the same test case name AND
+// same test name (but in different namespaces), the second test will
+// fail.
+
+namespace foo {
+
+class MixedUpTestCaseTest : public testing::Test {
+};
+
+TEST_F(MixedUpTestCaseTest, FirstTestFromNamespaceFoo) {}
+TEST_F(MixedUpTestCaseTest, SecondTestFromNamespaceFoo) {}
+
+class MixedUpTestCaseWithSameTestNameTest : public testing::Test {
+};
+
+TEST_F(MixedUpTestCaseWithSameTestNameTest,
+ TheSecondTestWithThisNameShouldFail) {}
+
+} // namespace foo
+
+namespace bar {
+
+class MixedUpTestCaseTest : public testing::Test {
+};
+
+// The following two tests are expected to fail. We rely on the
+// golden file to check that Google Test generates the right error message.
+TEST_F(MixedUpTestCaseTest, ThisShouldFail) {}
+TEST_F(MixedUpTestCaseTest, ThisShouldFailToo) {}
+
+class MixedUpTestCaseWithSameTestNameTest : public testing::Test {
+};
+
+// Expected to fail. We rely on the golden file to check that Google Test
+// generates the right error message.
+TEST_F(MixedUpTestCaseWithSameTestNameTest,
+ TheSecondTestWithThisNameShouldFail) {}
+
+} // namespace bar
+
+// The following two test cases verify that Google Test catches the user
+// error of mixing TEST and TEST_F in the same test case. The first
+// test case checks the scenario where TEST_F appears before TEST, and
+// the second one checks where TEST appears before TEST_F.
+
+class TEST_F_before_TEST_in_same_test_case : public testing::Test {
+};
+
+TEST_F(TEST_F_before_TEST_in_same_test_case, DefinedUsingTEST_F) {}
+
+// Expected to fail. We rely on the golden file to check that Google Test
+// generates the right error message.
+TEST(TEST_F_before_TEST_in_same_test_case, DefinedUsingTESTAndShouldFail) {}
+
+class TEST_before_TEST_F_in_same_test_case : public testing::Test {
+};
+
+TEST(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST) {}
+
+// Expected to fail. We rely on the golden file to check that Google Test
+// generates the right error message.
+TEST_F(TEST_before_TEST_F_in_same_test_case, DefinedUsingTEST_FAndShouldFail) {
+}
+
+// Used for testing EXPECT_NONFATAL_FAILURE() and EXPECT_FATAL_FAILURE().
+int global_integer = 0;
+
+// Tests that EXPECT_NONFATAL_FAILURE() can reference global variables.
+TEST(ExpectNonfatalFailureTest, CanReferenceGlobalVariables) {
+ global_integer = 0;
+ EXPECT_NONFATAL_FAILURE({
+ EXPECT_EQ(1, global_integer) << "Expected non-fatal failure.";
+ }, "Expected non-fatal failure.");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() can reference local variables
+// (static or not).
+TEST(ExpectNonfatalFailureTest, CanReferenceLocalVariables) {
+ int m = 0;
+ static int n;
+ n = 1;
+ EXPECT_NONFATAL_FAILURE({
+ EXPECT_EQ(m, n) << "Expected non-fatal failure.";
+ }, "Expected non-fatal failure.");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() succeeds when there is exactly
+// one non-fatal failure and no fatal failure.
+TEST(ExpectNonfatalFailureTest, SucceedsWhenThereIsOneNonfatalFailure) {
+ EXPECT_NONFATAL_FAILURE({
+ ADD_FAILURE() << "Expected non-fatal failure.";
+ }, "Expected non-fatal failure.");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when there is no
+// non-fatal failure.
+TEST(ExpectNonfatalFailureTest, FailsWhenThereIsNoNonfatalFailure) {
+ printf("(expecting a failure)\n");
+ EXPECT_NONFATAL_FAILURE({
+ }, "");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when there are two
+// non-fatal failures.
+TEST(ExpectNonfatalFailureTest, FailsWhenThereAreTwoNonfatalFailures) {
+ printf("(expecting a failure)\n");
+ EXPECT_NONFATAL_FAILURE({
+ ADD_FAILURE() << "Expected non-fatal failure 1.";
+ ADD_FAILURE() << "Expected non-fatal failure 2.";
+ }, "");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when there is one fatal
+// failure.
+TEST(ExpectNonfatalFailureTest, FailsWhenThereIsOneFatalFailure) {
+ printf("(expecting a failure)\n");
+ EXPECT_NONFATAL_FAILURE({
+ FAIL() << "Expected fatal failure.";
+ }, "");
+}
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being
+// tested returns.
+TEST(ExpectNonfatalFailureTest, FailsWhenStatementReturns) {
+ printf("(expecting a failure)\n");
+ EXPECT_NONFATAL_FAILURE({
+ return;
+ }, "");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Tests that EXPECT_NONFATAL_FAILURE() fails when the statement being
+// tested throws.
+TEST(ExpectNonfatalFailureTest, FailsWhenStatementThrows) {
+ printf("(expecting a failure)\n");
+ try {
+ EXPECT_NONFATAL_FAILURE({
+ throw 0;
+ }, "");
+ } catch(int) { // NOLINT
+ }
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Tests that EXPECT_FATAL_FAILURE() can reference global variables.
+TEST(ExpectFatalFailureTest, CanReferenceGlobalVariables) {
+ global_integer = 0;
+ EXPECT_FATAL_FAILURE({
+ ASSERT_EQ(1, global_integer) << "Expected fatal failure.";
+ }, "Expected fatal failure.");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() can reference local static
+// variables.
+TEST(ExpectFatalFailureTest, CanReferenceLocalStaticVariables) {
+ static int n;
+ n = 1;
+ EXPECT_FATAL_FAILURE({
+ ASSERT_EQ(0, n) << "Expected fatal failure.";
+ }, "Expected fatal failure.");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() succeeds when there is exactly
+// one fatal failure and no non-fatal failure.
+TEST(ExpectFatalFailureTest, SucceedsWhenThereIsOneFatalFailure) {
+ EXPECT_FATAL_FAILURE({
+ FAIL() << "Expected fatal failure.";
+ }, "Expected fatal failure.");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() fails when there is no fatal
+// failure.
+TEST(ExpectFatalFailureTest, FailsWhenThereIsNoFatalFailure) {
+ printf("(expecting a failure)\n");
+ EXPECT_FATAL_FAILURE({
+ }, "");
+}
+
+// A helper for generating a fatal failure.
+void FatalFailure() {
+ FAIL() << "Expected fatal failure.";
+}
+
+// Tests that EXPECT_FATAL_FAILURE() fails when there are two
+// fatal failures.
+TEST(ExpectFatalFailureTest, FailsWhenThereAreTwoFatalFailures) {
+ printf("(expecting a failure)\n");
+ EXPECT_FATAL_FAILURE({
+ FatalFailure();
+ FatalFailure();
+ }, "");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() fails when there is one non-fatal
+// failure.
+TEST(ExpectFatalFailureTest, FailsWhenThereIsOneNonfatalFailure) {
+ printf("(expecting a failure)\n");
+ EXPECT_FATAL_FAILURE({
+ ADD_FAILURE() << "Expected non-fatal failure.";
+ }, "");
+}
+
+// Tests that EXPECT_FATAL_FAILURE() fails when the statement being
+// tested returns.
+TEST(ExpectFatalFailureTest, FailsWhenStatementReturns) {
+ printf("(expecting a failure)\n");
+ EXPECT_FATAL_FAILURE({
+ return;
+ }, "");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Tests that EXPECT_FATAL_FAILURE() fails when the statement being
+// tested throws.
+TEST(ExpectFatalFailureTest, FailsWhenStatementThrows) {
+ printf("(expecting a failure)\n");
+ try {
+ EXPECT_FATAL_FAILURE({
+ throw 0;
+ }, "");
+ } catch(int) { // NOLINT
+ }
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// This #ifdef block tests the output of typed tests.
+#if GTEST_HAS_TYPED_TEST
+
+template <typename T>
+class TypedTest : public testing::Test {
+};
+
+TYPED_TEST_CASE(TypedTest, testing::Types<int>);
+
+TYPED_TEST(TypedTest, Success) {
+ EXPECT_EQ(0, TypeParam());
+}
+
+TYPED_TEST(TypedTest, Failure) {
+ EXPECT_EQ(1, TypeParam()) << "Expected failure";
+}
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// This #ifdef block tests the output of type-parameterized tests.
+#if GTEST_HAS_TYPED_TEST_P
+
+template <typename T>
+class TypedTestP : public testing::Test {
+};
+
+TYPED_TEST_CASE_P(TypedTestP);
+
+TYPED_TEST_P(TypedTestP, Success) {
+ EXPECT_EQ(0U, TypeParam());
+}
+
+TYPED_TEST_P(TypedTestP, Failure) {
+ EXPECT_EQ(1U, TypeParam()) << "Expected failure";
+}
+
+REGISTER_TYPED_TEST_CASE_P(TypedTestP, Success, Failure);
+
+typedef testing::Types<unsigned char, unsigned int> UnsignedTypes;
+INSTANTIATE_TYPED_TEST_CASE_P(Unsigned, TypedTestP, UnsignedTypes);
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#if GTEST_HAS_DEATH_TEST
+
+// We rely on the golden file to verify that tests whose test case
+// name ends with DeathTest are run first.
+
+TEST(ADeathTest, ShouldRunFirst) {
+}
+
+#if GTEST_HAS_TYPED_TEST
+
+// We rely on the golden file to verify that typed tests whose test
+// case name ends with DeathTest are run first.
+
+template <typename T>
+class ATypedDeathTest : public testing::Test {
+};
+
+typedef testing::Types<int, double> NumericTypes;
+TYPED_TEST_CASE(ATypedDeathTest, NumericTypes);
+
+TYPED_TEST(ATypedDeathTest, ShouldRunFirst) {
+}
+
+#endif // GTEST_HAS_TYPED_TEST
+
+#if GTEST_HAS_TYPED_TEST_P
+
+
+// We rely on the golden file to verify that type-parameterized tests
+// whose test case name ends with DeathTest are run first.
+
+template <typename T>
+class ATypeParamDeathTest : public testing::Test {
+};
+
+TYPED_TEST_CASE_P(ATypeParamDeathTest);
+
+TYPED_TEST_P(ATypeParamDeathTest, ShouldRunFirst) {
+}
+
+REGISTER_TYPED_TEST_CASE_P(ATypeParamDeathTest, ShouldRunFirst);
+
+INSTANTIATE_TYPED_TEST_CASE_P(My, ATypeParamDeathTest, NumericTypes);
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+#endif // GTEST_HAS_DEATH_TEST
+
+// Tests various failure conditions of
+// EXPECT_{,NON}FATAL_FAILURE{,_ON_ALL_THREADS}.
+class ExpectFailureTest : public testing::Test {
+ public: // Must be public and not protected due to a bug in g++ 3.4.2.
+ enum FailureMode {
+ FATAL_FAILURE,
+ NONFATAL_FAILURE
+ };
+ static void AddFailure(FailureMode failure) {
+ if (failure == FATAL_FAILURE) {
+ FAIL() << "Expected fatal failure.";
+ } else {
+ ADD_FAILURE() << "Expected non-fatal failure.";
+ }
+ }
+};
+
+TEST_F(ExpectFailureTest, ExpectFatalFailure) {
+ // Expected fatal failure, but succeeds.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE(SUCCEED(), "Expected fatal failure.");
+ // Expected fatal failure, but got a non-fatal failure.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Expected non-fatal "
+ "failure.");
+ // Wrong message.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE(AddFailure(FATAL_FAILURE), "Some other fatal failure "
+ "expected.");
+}
+
+TEST_F(ExpectFailureTest, ExpectNonFatalFailure) {
+ // Expected non-fatal failure, but succeeds.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE(SUCCEED(), "Expected non-fatal failure.");
+ // Expected non-fatal failure, but got a fatal failure.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE(AddFailure(FATAL_FAILURE), "Expected fatal failure.");
+ // Wrong message.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE(AddFailure(NONFATAL_FAILURE), "Some other non-fatal "
+ "failure.");
+}
+
+#if GTEST_IS_THREADSAFE
+
+class ExpectFailureWithThreadsTest : public ExpectFailureTest {
+ protected:
+ static void AddFailureInOtherThread(FailureMode failure) {
+ ThreadWithParam<FailureMode> thread(&AddFailure, failure, NULL);
+ thread.Join();
+ }
+};
+
+TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailure) {
+ // We only intercept the current thread.
+ printf("(expecting 2 failures)\n");
+ EXPECT_FATAL_FAILURE(AddFailureInOtherThread(FATAL_FAILURE),
+ "Expected fatal failure.");
+}
+
+TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailure) {
+ // We only intercept the current thread.
+ printf("(expecting 2 failures)\n");
+ EXPECT_NONFATAL_FAILURE(AddFailureInOtherThread(NONFATAL_FAILURE),
+ "Expected non-fatal failure.");
+}
+
+typedef ExpectFailureWithThreadsTest ScopedFakeTestPartResultReporterTest;
+
+// Tests that the ScopedFakeTestPartResultReporter only catches failures from
+// the current thread if it is instantiated with INTERCEPT_ONLY_CURRENT_THREAD.
+TEST_F(ScopedFakeTestPartResultReporterTest, InterceptOnlyCurrentThread) {
+ printf("(expecting 2 failures)\n");
+ TestPartResultArray results;
+ {
+ ScopedFakeTestPartResultReporter reporter(
+ ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD,
+ &results);
+ AddFailureInOtherThread(FATAL_FAILURE);
+ AddFailureInOtherThread(NONFATAL_FAILURE);
+ }
+ // The two failures should not have been intercepted.
+ EXPECT_EQ(0, results.size()) << "This shouldn't fail.";
+}
+
+#endif // GTEST_IS_THREADSAFE
+
+TEST_F(ExpectFailureTest, ExpectFatalFailureOnAllThreads) {
+ // Expected fatal failure, but succeeds.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected fatal failure.");
+ // Expected fatal failure, but got a non-fatal failure.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE),
+ "Expected non-fatal failure.");
+ // Wrong message.
+ printf("(expecting 1 failure)\n");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE),
+ "Some other fatal failure expected.");
+}
+
+TEST_F(ExpectFailureTest, ExpectNonFatalFailureOnAllThreads) {
+ // Expected non-fatal failure, but succeeds.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(SUCCEED(), "Expected non-fatal "
+ "failure.");
+ // Expected non-fatal failure, but got a fatal failure.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(FATAL_FAILURE),
+ "Expected fatal failure.");
+ // Wrong message.
+ printf("(expecting 1 failure)\n");
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddFailure(NONFATAL_FAILURE),
+ "Some other non-fatal failure.");
+}
+
+
+// Two test environments for testing testing::AddGlobalTestEnvironment().
+
+class FooEnvironment : public testing::Environment {
+ public:
+ virtual void SetUp() {
+ printf("%s", "FooEnvironment::SetUp() called.\n");
+ }
+
+ virtual void TearDown() {
+ printf("%s", "FooEnvironment::TearDown() called.\n");
+ FAIL() << "Expected fatal failure.";
+ }
+};
+
+class BarEnvironment : public testing::Environment {
+ public:
+ virtual void SetUp() {
+ printf("%s", "BarEnvironment::SetUp() called.\n");
+ }
+
+ virtual void TearDown() {
+ printf("%s", "BarEnvironment::TearDown() called.\n");
+ ADD_FAILURE() << "Expected non-fatal failure.";
+ }
+};
+
+GTEST_DEFINE_bool_(internal_skip_environment_and_ad_hoc_tests, false,
+ "This flag causes the program to skip test environment "
+ "tests and ad hoc tests.");
+
+// The main function.
+//
+// The idea is to use Google Test to run all the tests we have defined (some
+// of them are intended to fail), and then compare the test results
+// with the "golden" file.
+int main(int argc, char **argv) {
+ testing::GTEST_FLAG(print_time) = false;
+
+ // We just run the tests, knowing some of them are intended to fail.
+ // We will use a separate Python script to compare the output of
+ // this program with the golden file.
+
+ // It's hard to test InitGoogleTest() directly, as it has many
+ // global side effects. The following line serves as a sanity test
+ // for it.
+ testing::InitGoogleTest(&argc, argv);
+ if (argc >= 2 &&
+ String(argv[1]) == "--gtest_internal_skip_environment_and_ad_hoc_tests")
+ GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests) = true;
+
+#if GTEST_HAS_DEATH_TEST
+ if (testing::internal::GTEST_FLAG(internal_run_death_test) != "") {
+ // Skip the usual output capturing if we're running as the child
+ // process of an threadsafe-style death test.
+#if GTEST_OS_WINDOWS
+ posix::FReopen("nul:", "w", stdout);
+#else
+ posix::FReopen("/dev/null", "w", stdout);
+#endif // GTEST_OS_WINDOWS
+ return RUN_ALL_TESTS();
+ }
+#endif // GTEST_HAS_DEATH_TEST
+
+ if (GTEST_FLAG(internal_skip_environment_and_ad_hoc_tests))
+ return RUN_ALL_TESTS();
+
+ // Registers two global test environments.
+ // The golden file verifies that they are set up in the order they
+ // are registered, and torn down in the reverse order.
+ testing::AddGlobalTestEnvironment(new FooEnvironment);
+ testing::AddGlobalTestEnvironment(new BarEnvironment);
+
+ return RunAllTests();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_output_test_golden_lin.txt b/Source/ThirdParty/gtest/test/gtest_output_test_golden_lin.txt
new file mode 100644
index 000000000..ec60437ac
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_output_test_golden_lin.txt
@@ -0,0 +1,696 @@
+The non-test part of the code is expected to have 2 failures.
+
+gtest_output_test_.cc:#: Failure
+Value of: false
+ Actual: false
+Expected: true
+gtest_output_test_.cc:#: Failure
+Value of: 3
+Expected: 2
+[==========] Running 60 tests from 25 test cases.
+[----------] Global test environment set-up.
+FooEnvironment::SetUp() called.
+BarEnvironment::SetUp() called.
+[----------] 1 test from ADeathTest
+[ RUN ] ADeathTest.ShouldRunFirst
+[ OK ] ADeathTest.ShouldRunFirst
+[----------] 1 test from ATypedDeathTest/0, where TypeParam = int
+[ RUN ] ATypedDeathTest/0.ShouldRunFirst
+[ OK ] ATypedDeathTest/0.ShouldRunFirst
+[----------] 1 test from ATypedDeathTest/1, where TypeParam = double
+[ RUN ] ATypedDeathTest/1.ShouldRunFirst
+[ OK ] ATypedDeathTest/1.ShouldRunFirst
+[----------] 1 test from My/ATypeParamDeathTest/0, where TypeParam = int
+[ RUN ] My/ATypeParamDeathTest/0.ShouldRunFirst
+[ OK ] My/ATypeParamDeathTest/0.ShouldRunFirst
+[----------] 1 test from My/ATypeParamDeathTest/1, where TypeParam = double
+[ RUN ] My/ATypeParamDeathTest/1.ShouldRunFirst
+[ OK ] My/ATypeParamDeathTest/1.ShouldRunFirst
+[----------] 2 tests from PassingTest
+[ RUN ] PassingTest.PassingTest1
+[ OK ] PassingTest.PassingTest1
+[ RUN ] PassingTest.PassingTest2
+[ OK ] PassingTest.PassingTest2
+[----------] 3 tests from FatalFailureTest
+[ RUN ] FatalFailureTest.FatalFailureInSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: Failure
+Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
+[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: Failure
+Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
+[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine
+(expecting a failure on false)
+gtest_output_test_.cc:#: Failure
+Value of: false
+ Actual: false
+Expected: true
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
+[----------] 1 test from LoggingTest
+[ RUN ] LoggingTest.InterleavingLoggingAndAssertions
+(expecting 2 failures on (3) >= (a[i]))
+i == 0
+i == 1
+gtest_output_test_.cc:#: Failure
+Expected: (3) >= (a[i]), actual: 3 vs 9
+i == 2
+i == 3
+gtest_output_test_.cc:#: Failure
+Expected: (3) >= (a[i]), actual: 3 vs 6
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions
+[----------] 6 tests from SCOPED_TRACETest
+[ RUN ] SCOPED_TRACETest.ObeysScopes
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and shouldn't have a trace.
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should have a trace.
+Google Test trace:
+gtest_output_test_.cc:#: Expected trace
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and shouldn't have a trace.
+[ FAILED ] SCOPED_TRACETest.ObeysScopes
+[ RUN ] SCOPED_TRACETest.WorksInLoop
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 1
+Expected: 2
+Google Test trace:
+gtest_output_test_.cc:#: i = 1
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: i = 2
+[ FAILED ] SCOPED_TRACETest.WorksInLoop
+[ RUN ] SCOPED_TRACETest.WorksInSubroutine
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 1
+Expected: 2
+Google Test trace:
+gtest_output_test_.cc:#: n = 1
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: n = 2
+[ FAILED ] SCOPED_TRACETest.WorksInSubroutine
+[ RUN ] SCOPED_TRACETest.CanBeNested
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: n = 2
+gtest_output_test_.cc:#:
+[ FAILED ] SCOPED_TRACETest.CanBeNested
+[ RUN ] SCOPED_TRACETest.CanBeRepeated
+(expected to fail)
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should contain trace point A.
+Google Test trace:
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should contain trace point A and B.
+Google Test trace:
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should contain trace point A, B, and C.
+Google Test trace:
+gtest_output_test_.cc:#: C
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: Failure
+Failed
+This failure is expected, and should contain trace point A, B, and D.
+Google Test trace:
+gtest_output_test_.cc:#: D
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+[ FAILED ] SCOPED_TRACETest.CanBeRepeated
+[ RUN ] SCOPED_TRACETest.WorksConcurrently
+(expecting 6 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1 (in thread B, only trace B alive).
+Google Test trace:
+gtest_output_test_.cc:#: Trace B
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2 (in thread A, trace A & B both alive).
+Google Test trace:
+gtest_output_test_.cc:#: Trace A
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #3 (in thread B, trace A & B both alive).
+Google Test trace:
+gtest_output_test_.cc:#: Trace B
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #4 (in thread B, only trace A alive).
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #5 (in thread A, only trace A alive).
+Google Test trace:
+gtest_output_test_.cc:#: Trace A
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #6 (in thread A, no trace alive).
+[ FAILED ] SCOPED_TRACETest.WorksConcurrently
+[----------] 1 test from NonFatalFailureInFixtureConstructorTest
+[ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor
+(expecting 5 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1, in the test fixture c'tor.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2, in SetUp().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #3, in the test body.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #4, in TearDown.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #5, in the test fixture d'tor.
+[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor
+[----------] 1 test from FatalFailureInFixtureConstructorTest
+[ RUN ] FatalFailureInFixtureConstructorTest.FailureInConstructor
+(expecting 2 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1, in the test fixture c'tor.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2, in the test fixture d'tor.
+[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor
+[----------] 1 test from NonFatalFailureInSetUpTest
+[ RUN ] NonFatalFailureInSetUpTest.FailureInSetUp
+(expecting 4 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1, in SetUp().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2, in the test function.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #3, in TearDown().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #4, in the test fixture d'tor.
+[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp
+[----------] 1 test from FatalFailureInSetUpTest
+[ RUN ] FatalFailureInSetUpTest.FailureInSetUp
+(expecting 3 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #1, in SetUp().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #2, in TearDown().
+gtest_output_test_.cc:#: Failure
+Failed
+Expected failure #3, in the test fixture d'tor.
+[ FAILED ] FatalFailureInSetUpTest.FailureInSetUp
+[----------] 4 tests from MixedUpTestCaseTest
+[ RUN ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo
+[ OK ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo
+[ RUN ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo
+[ OK ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo
+[ RUN ] MixedUpTestCaseTest.ThisShouldFail
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseTest,
+you defined test FirstTestFromNamespaceFoo and test ThisShouldFail
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[ FAILED ] MixedUpTestCaseTest.ThisShouldFail
+[ RUN ] MixedUpTestCaseTest.ThisShouldFailToo
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseTest,
+you defined test FirstTestFromNamespaceFoo and test ThisShouldFailToo
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo
+[----------] 2 tests from MixedUpTestCaseWithSameTestNameTest
+[ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[ OK ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseWithSameTestNameTest,
+you defined test TheSecondTestWithThisNameShouldFail and test TheSecondTestWithThisNameShouldFail
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[----------] 2 tests from TEST_F_before_TEST_in_same_test_case
+[ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F
+[ OK ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F
+[ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class, so mixing TEST_F and TEST in the same test case is
+illegal. In test case TEST_F_before_TEST_in_same_test_case,
+test DefinedUsingTEST_F is defined using TEST_F but
+test DefinedUsingTESTAndShouldFail is defined using TEST. You probably
+want to change the TEST to TEST_F or move it to another test
+case.
+[ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+[----------] 2 tests from TEST_before_TEST_F_in_same_test_case
+[ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST
+[ OK ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST
+[ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+gtest.cc:#: Failure
+Failed
+All tests in the same test case must use the same test fixture
+class, so mixing TEST_F and TEST in the same test case is
+illegal. In test case TEST_before_TEST_F_in_same_test_case,
+test DefinedUsingTEST_FAndShouldFail is defined using TEST_F but
+test DefinedUsingTEST is defined using TEST. You probably
+want to change the TEST to TEST_F or move it to another test
+case.
+[ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+[----------] 8 tests from ExpectNonfatalFailureTest
+[ RUN ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables
+[ OK ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables
+[ RUN ] ExpectNonfatalFailureTest.CanReferenceLocalVariables
+[ OK ] ExpectNonfatalFailureTest.CanReferenceLocalVariables
+[ RUN ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure
+[ OK ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 2 failures
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure 1.
+
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure 2.
+
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementReturns
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementThrows
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows
+[----------] 8 tests from ExpectFatalFailureTest
+[ RUN ] ExpectFatalFailureTest.CanReferenceGlobalVariables
+[ OK ] ExpectFatalFailureTest.CanReferenceGlobalVariables
+[ RUN ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables
+[ OK ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables
+[ RUN ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure
+[ OK ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure
+[ RUN ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+[ RUN ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 2 failures
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+[ RUN ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+[ RUN ] ExpectFatalFailureTest.FailsWhenStatementReturns
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns
+[ RUN ] ExpectFatalFailureTest.FailsWhenStatementThrows
+(expecting a failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows
+[----------] 2 tests from TypedTest/0, where TypeParam = int
+[ RUN ] TypedTest/0.Success
+[ OK ] TypedTest/0.Success
+[ RUN ] TypedTest/0.Failure
+gtest_output_test_.cc:#: Failure
+Value of: TypeParam()
+ Actual: 0
+Expected: 1
+Expected failure
+[ FAILED ] TypedTest/0.Failure
+[----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char
+[ RUN ] Unsigned/TypedTestP/0.Success
+[ OK ] Unsigned/TypedTestP/0.Success
+[ RUN ] Unsigned/TypedTestP/0.Failure
+gtest_output_test_.cc:#: Failure
+Value of: TypeParam()
+ Actual: \0
+Expected: 1U
+Which is: 1
+Expected failure
+[ FAILED ] Unsigned/TypedTestP/0.Failure
+[----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int
+[ RUN ] Unsigned/TypedTestP/1.Success
+[ OK ] Unsigned/TypedTestP/1.Success
+[ RUN ] Unsigned/TypedTestP/1.Failure
+gtest_output_test_.cc:#: Failure
+Value of: TypeParam()
+ Actual: 0
+Expected: 1U
+Which is: 1
+Expected failure
+[ FAILED ] Unsigned/TypedTestP/1.Failure
+[----------] 4 tests from ExpectFailureTest
+[ RUN ] ExpectFailureTest.ExpectFatalFailure
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure containing "Some other fatal failure expected."
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[ FAILED ] ExpectFailureTest.ExpectFatalFailure
+[ RUN ] ExpectFailureTest.ExpectNonFatalFailure
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure containing "Some other non-fatal failure."
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure
+[ RUN ] ExpectFailureTest.ExpectFatalFailureOnAllThreads
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 fatal failure containing "Some other fatal failure expected."
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads
+[ RUN ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure containing "Some other non-fatal failure."
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+[----------] 2 tests from ExpectFailureWithThreadsTest
+[ RUN ] ExpectFailureWithThreadsTest.ExpectFatalFailure
+(expecting 2 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected fatal failure.
+gtest.cc:#: Failure
+Expected: 1 fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure
+[ RUN ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure
+(expecting 2 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected non-fatal failure.
+gtest.cc:#: Failure
+Expected: 1 non-fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure
+[----------] 1 test from ScopedFakeTestPartResultReporterTest
+[ RUN ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
+(expecting 2 failures)
+gtest_output_test_.cc:#: Failure
+Failed
+Expected fatal failure.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected non-fatal failure.
+[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
+[----------] Global test environment tear-down
+BarEnvironment::TearDown() called.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected non-fatal failure.
+FooEnvironment::TearDown() called.
+gtest_output_test_.cc:#: Failure
+Failed
+Expected fatal failure.
+[==========] 60 tests from 25 test cases ran.
+[ PASSED ] 21 tests.
+[ FAILED ] 39 tests, listed below:
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions
+[ FAILED ] SCOPED_TRACETest.ObeysScopes
+[ FAILED ] SCOPED_TRACETest.WorksInLoop
+[ FAILED ] SCOPED_TRACETest.WorksInSubroutine
+[ FAILED ] SCOPED_TRACETest.CanBeNested
+[ FAILED ] SCOPED_TRACETest.CanBeRepeated
+[ FAILED ] SCOPED_TRACETest.WorksConcurrently
+[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor
+[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor
+[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp
+[ FAILED ] FatalFailureInSetUpTest.FailureInSetUp
+[ FAILED ] MixedUpTestCaseTest.ThisShouldFail
+[ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo
+[ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+[ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns
+[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows
+[ FAILED ] TypedTest/0.Failure, where TypeParam = int
+[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char
+[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int
+[ FAILED ] ExpectFailureTest.ExpectFatalFailure
+[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure
+[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads
+[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+[ FAILED ] ExpectFailureWithThreadsTest.ExpectFatalFailure
+[ FAILED ] ExpectFailureWithThreadsTest.ExpectNonFatalFailure
+[ FAILED ] ScopedFakeTestPartResultReporterTest.InterceptOnlyCurrentThread
+
+39 FAILED TESTS
+ YOU HAVE 1 DISABLED TEST
+
+Note: Google Test filter = FatalFailureTest.*:LoggingTest.*
+[==========] Running 4 tests from 2 test cases.
+[----------] Global test environment set-up.
+[----------] 3 tests from FatalFailureTest
+[ RUN ] FatalFailureTest.FatalFailureInSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: Failure
+Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms)
+[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: Failure
+Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine (? ms)
+[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine
+(expecting a failure on false)
+gtest_output_test_.cc:#: Failure
+Value of: false
+ Actual: false
+Expected: true
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine (? ms)
+[----------] 3 tests from FatalFailureTest (? ms total)
+
+[----------] 1 test from LoggingTest
+[ RUN ] LoggingTest.InterleavingLoggingAndAssertions
+(expecting 2 failures on (3) >= (a[i]))
+i == 0
+i == 1
+gtest_output_test_.cc:#: Failure
+Expected: (3) >= (a[i]), actual: 3 vs 9
+i == 2
+i == 3
+gtest_output_test_.cc:#: Failure
+Expected: (3) >= (a[i]), actual: 3 vs 6
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions (? ms)
+[----------] 1 test from LoggingTest (? ms total)
+
+[----------] Global test environment tear-down
+[==========] 4 tests from 2 test cases ran. (? ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 4 tests, listed below:
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions
+
+ 4 FAILED TESTS
+ YOU HAVE 1 DISABLED TEST
+
+Note: Google Test filter = *DISABLED_*
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from DisabledTestsWarningTest
+[ RUN ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning
+[ OK ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran.
+[ PASSED ] 1 test.
+Note: Google Test filter = PassingTest.*
+Note: This is test shard 1 of 2.
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from PassingTest
+[ RUN ] PassingTest.PassingTest2
+[ OK ] PassingTest.PassingTest2
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran.
+[ PASSED ] 1 test.
+
+ YOU HAVE 1 DISABLED TEST
+
diff --git a/Source/ThirdParty/gtest/test/gtest_output_test_golden_win.txt b/Source/ThirdParty/gtest/test/gtest_output_test_golden_win.txt
new file mode 100644
index 000000000..313c3aafc
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_output_test_golden_win.txt
@@ -0,0 +1,605 @@
+The non-test part of the code is expected to have 2 failures.
+
+gtest_output_test_.cc:#: error: Value of: false
+ Actual: false
+Expected: true
+gtest_output_test_.cc:#: error: Value of: 3
+Expected: 2
+[==========] Running 61 tests from 27 test cases.
+[----------] Global test environment set-up.
+FooEnvironment::SetUp() called.
+BarEnvironment::SetUp() called.
+[----------] 1 test from ADeathTest
+[ RUN ] ADeathTest.ShouldRunFirst
+[ OK ] ADeathTest.ShouldRunFirst
+[----------] 1 test from ATypedDeathTest/0, where TypeParam = int
+[ RUN ] ATypedDeathTest/0.ShouldRunFirst
+[ OK ] ATypedDeathTest/0.ShouldRunFirst
+[----------] 1 test from ATypedDeathTest/1, where TypeParam = double
+[ RUN ] ATypedDeathTest/1.ShouldRunFirst
+[ OK ] ATypedDeathTest/1.ShouldRunFirst
+[----------] 1 test from My/ATypeParamDeathTest/0, where TypeParam = int
+[ RUN ] My/ATypeParamDeathTest/0.ShouldRunFirst
+[ OK ] My/ATypeParamDeathTest/0.ShouldRunFirst
+[----------] 1 test from My/ATypeParamDeathTest/1, where TypeParam = double
+[ RUN ] My/ATypeParamDeathTest/1.ShouldRunFirst
+[ OK ] My/ATypeParamDeathTest/1.ShouldRunFirst
+[----------] 2 tests from PassingTest
+[ RUN ] PassingTest.PassingTest1
+[ OK ] PassingTest.PassingTest1
+[ RUN ] PassingTest.PassingTest2
+[ OK ] PassingTest.PassingTest2
+[----------] 3 tests from FatalFailureTest
+[ RUN ] FatalFailureTest.FatalFailureInSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: error: Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
+[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: error: Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
+[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine
+(expecting a failure on false)
+gtest_output_test_.cc:#: error: Value of: false
+ Actual: false
+Expected: true
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
+[----------] 1 test from LoggingTest
+[ RUN ] LoggingTest.InterleavingLoggingAndAssertions
+(expecting 2 failures on (3) >= (a[i]))
+i == 0
+i == 1
+gtest_output_test_.cc:#: error: Expected: (3) >= (a[i]), actual: 3 vs 9
+i == 2
+i == 3
+gtest_output_test_.cc:#: error: Expected: (3) >= (a[i]), actual: 3 vs 6
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions
+[----------] 5 tests from SCOPED_TRACETest
+[ RUN ] SCOPED_TRACETest.ObeysScopes
+(expected to fail)
+gtest_output_test_.cc:#: error: Failed
+This failure is expected, and shouldn't have a trace.
+gtest_output_test_.cc:#: error: Failed
+This failure is expected, and should have a trace.
+Google Test trace:
+gtest_output_test_.cc:#: Expected trace
+gtest_output_test_.cc:#: error: Failed
+This failure is expected, and shouldn't have a trace.
+[ FAILED ] SCOPED_TRACETest.ObeysScopes
+[ RUN ] SCOPED_TRACETest.WorksInLoop
+(expected to fail)
+gtest_output_test_.cc:#: error: Value of: n
+ Actual: 1
+Expected: 2
+Google Test trace:
+gtest_output_test_.cc:#: i = 1
+gtest_output_test_.cc:#: error: Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: i = 2
+[ FAILED ] SCOPED_TRACETest.WorksInLoop
+[ RUN ] SCOPED_TRACETest.WorksInSubroutine
+(expected to fail)
+gtest_output_test_.cc:#: error: Value of: n
+ Actual: 1
+Expected: 2
+Google Test trace:
+gtest_output_test_.cc:#: n = 1
+gtest_output_test_.cc:#: error: Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: n = 2
+[ FAILED ] SCOPED_TRACETest.WorksInSubroutine
+[ RUN ] SCOPED_TRACETest.CanBeNested
+(expected to fail)
+gtest_output_test_.cc:#: error: Value of: n
+ Actual: 2
+Expected: 1
+Google Test trace:
+gtest_output_test_.cc:#: n = 2
+gtest_output_test_.cc:#:
+[ FAILED ] SCOPED_TRACETest.CanBeNested
+[ RUN ] SCOPED_TRACETest.CanBeRepeated
+(expected to fail)
+gtest_output_test_.cc:#: error: Failed
+This failure is expected, and should contain trace point A.
+Google Test trace:
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: error: Failed
+This failure is expected, and should contain trace point A and B.
+Google Test trace:
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: error: Failed
+This failure is expected, and should contain trace point A, B, and C.
+Google Test trace:
+gtest_output_test_.cc:#: C
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+gtest_output_test_.cc:#: error: Failed
+This failure is expected, and should contain trace point A, B, and D.
+Google Test trace:
+gtest_output_test_.cc:#: D
+gtest_output_test_.cc:#: B
+gtest_output_test_.cc:#: A
+[ FAILED ] SCOPED_TRACETest.CanBeRepeated
+[----------] 1 test from NonFatalFailureInFixtureConstructorTest
+[ RUN ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor
+(expecting 5 failures)
+gtest_output_test_.cc:#: error: Failed
+Expected failure #1, in the test fixture c'tor.
+gtest_output_test_.cc:#: error: Failed
+Expected failure #2, in SetUp().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #3, in the test body.
+gtest_output_test_.cc:#: error: Failed
+Expected failure #4, in TearDown.
+gtest_output_test_.cc:#: error: Failed
+Expected failure #5, in the test fixture d'tor.
+[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor
+[----------] 1 test from FatalFailureInFixtureConstructorTest
+[ RUN ] FatalFailureInFixtureConstructorTest.FailureInConstructor
+(expecting 2 failures)
+gtest_output_test_.cc:#: error: Failed
+Expected failure #1, in the test fixture c'tor.
+gtest_output_test_.cc:#: error: Failed
+Expected failure #2, in the test fixture d'tor.
+[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor
+[----------] 1 test from NonFatalFailureInSetUpTest
+[ RUN ] NonFatalFailureInSetUpTest.FailureInSetUp
+(expecting 4 failures)
+gtest_output_test_.cc:#: error: Failed
+Expected failure #1, in SetUp().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #2, in the test function.
+gtest_output_test_.cc:#: error: Failed
+Expected failure #3, in TearDown().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #4, in the test fixture d'tor.
+[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp
+[----------] 1 test from FatalFailureInSetUpTest
+[ RUN ] FatalFailureInSetUpTest.FailureInSetUp
+(expecting 3 failures)
+gtest_output_test_.cc:#: error: Failed
+Expected failure #1, in SetUp().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #2, in TearDown().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #3, in the test fixture d'tor.
+[ FAILED ] FatalFailureInSetUpTest.FailureInSetUp
+[----------] 1 test from ExceptionInFixtureCtorTest
+[ RUN ] ExceptionInFixtureCtorTest.ExceptionInFixtureCtor
+(expecting a failure on thrown exception in the test fixture's constructor)
+unknown file: error: Exception thrown with code 0xc0000005 in the test fixture's constructor.
+[----------] 1 test from ExceptionInSetUpTest
+[ RUN ] ExceptionInSetUpTest.ExceptionInSetUp
+(expecting 3 failures)
+unknown file: error: Exception thrown with code 0xc0000005 in SetUp().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #2, in TearDown().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #3, in the test fixture d'tor.
+[ FAILED ] ExceptionInSetUpTest.ExceptionInSetUp
+[----------] 2 tests from ExceptionInTestFunctionTest
+[ RUN ] ExceptionInTestFunctionTest.SEH
+(expecting 3 failures)
+unknown file: error: Exception thrown with code 0xc0000005 in the test body.
+gtest_output_test_.cc:#: error: Failed
+Expected failure #2, in TearDown().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #3, in the test fixture d'tor.
+[ FAILED ] ExceptionInTestFunctionTest.SEH
+[ RUN ] ExceptionInTestFunctionTest.CppException
+unknown file: error: Exception thrown with code 0xe06d7363 in the test body.
+gtest_output_test_.cc:#: error: Failed
+Expected failure #2, in TearDown().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #3, in the test fixture d'tor.
+[ FAILED ] ExceptionInTestFunctionTest.CppException
+[----------] 1 test from ExceptionInTearDownTest
+[ RUN ] ExceptionInTearDownTest.ExceptionInTearDown
+(expecting 2 failures)
+unknown file: error: Exception thrown with code 0xe06d7363 in TearDown().
+gtest_output_test_.cc:#: error: Failed
+Expected failure #2, in the test fixture d'tor.
+[ FAILED ] ExceptionInTearDownTest.ExceptionInTearDown
+[----------] 4 tests from MixedUpTestCaseTest
+[ RUN ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo
+[ OK ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo
+[ RUN ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo
+[ OK ] MixedUpTestCaseTest.SecondTestFromNamespaceFoo
+[ RUN ] MixedUpTestCaseTest.ThisShouldFail
+gtest.cc:#: error: Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseTest,
+you defined test FirstTestFromNamespaceFoo and test ThisShouldFail
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[ FAILED ] MixedUpTestCaseTest.ThisShouldFail
+[ RUN ] MixedUpTestCaseTest.ThisShouldFailToo
+gtest.cc:#: error: Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseTest,
+you defined test FirstTestFromNamespaceFoo and test ThisShouldFailToo
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo
+[----------] 2 tests from MixedUpTestCaseWithSameTestNameTest
+[ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[ OK ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[ RUN ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+gtest.cc:#: error: Failed
+All tests in the same test case must use the same test fixture
+class. However, in test case MixedUpTestCaseWithSameTestNameTest,
+you defined test TheSecondTestWithThisNameShouldFail and test TheSecondTestWithThisNameShouldFail
+using two different test fixture classes. This can happen if
+the two classes are from different namespaces or translation
+units and have the same name. You should probably rename one
+of the classes to put the tests into different test cases.
+[ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[----------] 2 tests from TEST_F_before_TEST_in_same_test_case
+[ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F
+[ OK ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTEST_F
+[ RUN ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+gtest.cc:#: error: Failed
+All tests in the same test case must use the same test fixture
+class, so mixing TEST_F and TEST in the same test case is
+illegal. In test case TEST_F_before_TEST_in_same_test_case,
+test DefinedUsingTEST_F is defined using TEST_F but
+test DefinedUsingTESTAndShouldFail is defined using TEST. You probably
+want to change the TEST to TEST_F or move it to another test
+case.
+[ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+[----------] 2 tests from TEST_before_TEST_F_in_same_test_case
+[ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST
+[ OK ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST
+[ RUN ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+gtest.cc:#: error: Failed
+All tests in the same test case must use the same test fixture
+class, so mixing TEST_F and TEST in the same test case is
+illegal. In test case TEST_before_TEST_F_in_same_test_case,
+test DefinedUsingTEST_FAndShouldFail is defined using TEST_F but
+test DefinedUsingTEST is defined using TEST. You probably
+want to change the TEST to TEST_F or move it to another test
+case.
+[ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+[----------] 8 tests from ExpectNonfatalFailureTest
+[ RUN ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables
+[ OK ] ExpectNonfatalFailureTest.CanReferenceGlobalVariables
+[ RUN ] ExpectNonfatalFailureTest.CanReferenceLocalVariables
+[ OK ] ExpectNonfatalFailureTest.CanReferenceLocalVariables
+[ RUN ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure
+[ OK ] ExpectNonfatalFailureTest.SucceedsWhenThereIsOneNonfatalFailure
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual: 2 failures
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure 1.
+
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure 2.
+
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementReturns
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns
+[ RUN ] ExpectNonfatalFailureTest.FailsWhenStatementThrows
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows
+[----------] 8 tests from ExpectFatalFailureTest
+[ RUN ] ExpectFatalFailureTest.CanReferenceGlobalVariables
+[ OK ] ExpectFatalFailureTest.CanReferenceGlobalVariables
+[ RUN ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables
+[ OK ] ExpectFatalFailureTest.CanReferenceLocalStaticVariables
+[ RUN ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure
+[ OK ] ExpectFatalFailureTest.SucceedsWhenThereIsOneFatalFailure
+[ RUN ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+[ RUN ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual: 2 failures
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+[ RUN ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+[ RUN ] ExpectFatalFailureTest.FailsWhenStatementReturns
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns
+[ RUN ] ExpectFatalFailureTest.FailsWhenStatementThrows
+(expecting a failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual: 0 failures
+[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows
+[----------] 2 tests from TypedTest/0, where TypeParam = int
+[ RUN ] TypedTest/0.Success
+[ OK ] TypedTest/0.Success
+[ RUN ] TypedTest/0.Failure
+gtest_output_test_.cc:#: error: Value of: TypeParam()
+ Actual: 0
+Expected: 1
+Expected failure
+[ FAILED ] TypedTest/0.Failure
+[----------] 2 tests from Unsigned/TypedTestP/0, where TypeParam = unsigned char
+[ RUN ] Unsigned/TypedTestP/0.Success
+[ OK ] Unsigned/TypedTestP/0.Success
+[ RUN ] Unsigned/TypedTestP/0.Failure
+gtest_output_test_.cc:#: error: Value of: TypeParam()
+ Actual: \0
+Expected: 1U
+Which is: 1
+Expected failure
+[ FAILED ] Unsigned/TypedTestP/0.Failure
+[----------] 2 tests from Unsigned/TypedTestP/1, where TypeParam = unsigned int
+[ RUN ] Unsigned/TypedTestP/1.Success
+[ OK ] Unsigned/TypedTestP/1.Success
+[ RUN ] Unsigned/TypedTestP/1.Failure
+gtest_output_test_.cc:#: error: Value of: TypeParam()
+ Actual: 0
+Expected: 1U
+Which is: 1
+Expected failure
+[ FAILED ] Unsigned/TypedTestP/1.Failure
+[----------] 4 tests from ExpectFailureTest
+[ RUN ] ExpectFailureTest.ExpectFatalFailure
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 fatal failure containing "Some other fatal failure expected."
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[ FAILED ] ExpectFailureTest.ExpectFatalFailure
+[ RUN ] ExpectFailureTest.ExpectNonFatalFailure
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure containing "Some other non-fatal failure."
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure
+[ RUN ] ExpectFailureTest.ExpectFatalFailureOnAllThreads
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 fatal failure
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 fatal failure containing "Some other fatal failure expected."
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads
+[ RUN ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Success:
+Succeeded
+
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure
+ Actual:
+gtest_output_test_.cc:#: Fatal failure:
+Failed
+Expected fatal failure.
+
+(expecting 1 failure)
+gtest.cc:#: error: Expected: 1 non-fatal failure containing "Some other non-fatal failure."
+ Actual:
+gtest_output_test_.cc:#: Non-fatal failure:
+Failed
+Expected non-fatal failure.
+
+[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+[----------] Global test environment tear-down
+BarEnvironment::TearDown() called.
+gtest_output_test_.cc:#: error: Failed
+Expected non-fatal failure.
+FooEnvironment::TearDown() called.
+gtest_output_test_.cc:#: error: Failed
+Expected fatal failure.
+[==========] 61 tests from 27 test cases ran.
+[ PASSED ] 21 tests.
+[ FAILED ] 40 tests, listed below:
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions
+[ FAILED ] SCOPED_TRACETest.ObeysScopes
+[ FAILED ] SCOPED_TRACETest.WorksInLoop
+[ FAILED ] SCOPED_TRACETest.WorksInSubroutine
+[ FAILED ] SCOPED_TRACETest.CanBeNested
+[ FAILED ] SCOPED_TRACETest.CanBeRepeated
+[ FAILED ] NonFatalFailureInFixtureConstructorTest.FailureInConstructor
+[ FAILED ] FatalFailureInFixtureConstructorTest.FailureInConstructor
+[ FAILED ] NonFatalFailureInSetUpTest.FailureInSetUp
+[ FAILED ] FatalFailureInSetUpTest.FailureInSetUp
+[ FAILED ] ExceptionInFixtureCtorTest.ExceptionInFixtureCtor
+[ FAILED ] ExceptionInSetUpTest.ExceptionInSetUp
+[ FAILED ] ExceptionInTestFunctionTest.SEH
+[ FAILED ] ExceptionInTestFunctionTest.CppException
+[ FAILED ] ExceptionInTearDownTest.ExceptionInTearDown
+[ FAILED ] MixedUpTestCaseTest.ThisShouldFail
+[ FAILED ] MixedUpTestCaseTest.ThisShouldFailToo
+[ FAILED ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
+[ FAILED ] TEST_F_before_TEST_in_same_test_case.DefinedUsingTESTAndShouldFail
+[ FAILED ] TEST_before_TEST_F_in_same_test_case.DefinedUsingTEST_FAndShouldFail
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsNoNonfatalFailure
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereAreTwoNonfatalFailures
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenThereIsOneFatalFailure
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementReturns
+[ FAILED ] ExpectNonfatalFailureTest.FailsWhenStatementThrows
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsNoFatalFailure
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereAreTwoFatalFailures
+[ FAILED ] ExpectFatalFailureTest.FailsWhenThereIsOneNonfatalFailure
+[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementReturns
+[ FAILED ] ExpectFatalFailureTest.FailsWhenStatementThrows
+[ FAILED ] TypedTest/0.Failure, where TypeParam = int
+[ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char
+[ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int
+[ FAILED ] ExpectFailureTest.ExpectFatalFailure
+[ FAILED ] ExpectFailureTest.ExpectNonFatalFailure
+[ FAILED ] ExpectFailureTest.ExpectFatalFailureOnAllThreads
+[ FAILED ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
+
+40 FAILED TESTS
+ YOU HAVE 1 DISABLED TEST
+
+Note: Google Test filter = FatalFailureTest.*:LoggingTest.*
+[==========] Running 4 tests from 2 test cases.
+[----------] Global test environment set-up.
+[----------] 3 tests from FatalFailureTest
+[ RUN ] FatalFailureTest.FatalFailureInSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: error: Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms)
+[ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine
+(expecting a failure that x should be 1)
+gtest_output_test_.cc:#: error: Value of: x
+ Actual: 2
+Expected: 1
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine (? ms)
+[ RUN ] FatalFailureTest.NonfatalFailureInSubroutine
+(expecting a failure on false)
+gtest_output_test_.cc:#: error: Value of: false
+ Actual: false
+Expected: true
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine (? ms)
+[----------] 3 tests from FatalFailureTest (? ms total)
+
+[----------] 1 test from LoggingTest
+[ RUN ] LoggingTest.InterleavingLoggingAndAssertions
+(expecting 2 failures on (3) >= (a[i]))
+i == 0
+i == 1
+gtest_output_test_.cc:#: error: Expected: (3) >= (a[i]), actual: 3 vs 9
+i == 2
+i == 3
+gtest_output_test_.cc:#: error: Expected: (3) >= (a[i]), actual: 3 vs 6
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions (? ms)
+[----------] 1 test from LoggingTest (? ms total)
+
+[----------] Global test environment tear-down
+[==========] 4 tests from 2 test cases ran. (? ms total)
+[ PASSED ] 0 tests.
+[ FAILED ] 4 tests, listed below:
+[ FAILED ] FatalFailureTest.FatalFailureInSubroutine
+[ FAILED ] FatalFailureTest.FatalFailureInNestedSubroutine
+[ FAILED ] FatalFailureTest.NonfatalFailureInSubroutine
+[ FAILED ] LoggingTest.InterleavingLoggingAndAssertions
+
+ 4 FAILED TESTS
+ YOU HAVE 1 DISABLED TEST
+
+Note: Google Test filter = *DISABLED_*
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from DisabledTestsWarningTest
+[ RUN ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning
+[ OK ] DisabledTestsWarningTest.DISABLED_AlsoRunDisabledTestsFlagSuppressesWarning
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran.
+[ PASSED ] 1 test.
+Note: Google Test filter = PassingTest.*
+Note: This is test shard 1 of 2.
+[==========] Running 1 test from 1 test case.
+[----------] Global test environment set-up.
+[----------] 1 test from PassingTest
+[ RUN ] PassingTest.PassingTest2
+[ OK ] PassingTest.PassingTest2
+[----------] Global test environment tear-down
+[==========] 1 test from 1 test case ran.
+[ PASSED ] 1 test.
+
+ YOU HAVE 1 DISABLED TEST
+
diff --git a/Source/ThirdParty/gtest/test/gtest_pred_impl_unittest.cc b/Source/ThirdParty/gtest/test/gtest_pred_impl_unittest.cc
new file mode 100644
index 000000000..e7ee54b56
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_pred_impl_unittest.cc
@@ -0,0 +1,2432 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command
+// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
+
+// Regression test for gtest_pred_impl.h
+//
+// This file is generated by a script and quite long. If you intend to
+// learn how Google Test works by reading its unit tests, read
+// gtest_unittest.cc instead.
+//
+// This is intended as a regression test for the Google Test predicate
+// assertions. We compile it as part of the gtest_unittest target
+// only to keep the implementation tidy and compact, as it is quite
+// involved to set up the stage for testing Google Test using Google
+// Test itself.
+//
+// Currently, gtest_unittest takes ~11 seconds to run in the testing
+// daemon. In the future, if it grows too large and needs much more
+// time to finish, we should consider separating this file into a
+// stand-alone regression test.
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+#include <gtest/gtest-spi.h>
+
+// A user-defined data type.
+struct Bool {
+ explicit Bool(int val) : value(val != 0) {}
+
+ bool operator>(int n) const { return value > Bool(n).value; }
+
+ Bool operator+(const Bool& rhs) const { return Bool(value + rhs.value); }
+
+ bool operator==(const Bool& rhs) const { return value == rhs.value; }
+
+ bool value;
+};
+
+// Enables Bool to be used in assertions.
+std::ostream& operator<<(std::ostream& os, const Bool& x) {
+ return os << (x.value ? "true" : "false");
+}
+
+// Sample functions/functors for testing unary predicate assertions.
+
+// A unary predicate function.
+template <typename T1>
+bool PredFunction1(T1 v1) {
+ return v1 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction1Int(int v1) {
+ return v1 > 0;
+}
+bool PredFunction1Bool(Bool v1) {
+ return v1 > 0;
+}
+
+// A unary predicate functor.
+struct PredFunctor1 {
+ template <typename T1>
+ bool operator()(const T1& v1) {
+ return v1 > 0;
+ }
+};
+
+// A unary predicate-formatter function.
+template <typename T1>
+testing::AssertionResult PredFormatFunction1(const char* e1,
+ const T1& v1) {
+ if (PredFunction1(v1))
+ return testing::AssertionSuccess();
+
+ testing::Message msg;
+ msg << e1
+ << " is expected to be positive, but evaluates to "
+ << v1 << ".";
+ return testing::AssertionFailure(msg);
+}
+
+// A unary predicate-formatter functor.
+struct PredFormatFunctor1 {
+ template <typename T1>
+ testing::AssertionResult operator()(const char* e1,
+ const T1& v1) const {
+ return PredFormatFunction1(e1, v1);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT1.
+
+class Predicate1Test : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+};
+
+bool Predicate1Test::expected_to_finish_;
+bool Predicate1Test::finished_;
+int Predicate1Test::n1_;
+
+typedef Predicate1Test EXPECT_PRED_FORMAT1Test;
+typedef Predicate1Test ASSERT_PRED_FORMAT1Test;
+typedef Predicate1Test EXPECT_PRED1Test;
+typedef Predicate1Test ASSERT_PRED1Test;
+
+// Tests a successful EXPECT_PRED1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED1(PredFunction1Int,
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED1(PredFunction1Bool,
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED1(PredFunctor1(),
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED1(PredFunctor1(),
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED1Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(PredFunction1Int,
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED1Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(PredFunction1Bool,
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED1Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(PredFunctor1(),
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED1Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(PredFunctor1(),
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED1(PredFunction1Int,
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED1(PredFunction1Bool,
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED1(PredFunctor1(),
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED1(PredFunctor1(),
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED1Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED1(PredFunction1Int,
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED1Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED1(PredFunction1Bool,
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED1Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED1(PredFunctor1(),
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED1Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED1(PredFunctor1(),
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT1(PredFormatFunction1,
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT1(PredFormatFunction1,
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT1(PredFormatFunctor1(),
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT1(PredFormatFunctor1(),
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT1(PredFormatFunction1,
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT1(PredFormatFunction1,
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT1(PredFormatFunctor1(),
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT1(PredFormatFunctor1(),
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT1(PredFormatFunction1,
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT1(PredFormatFunction1,
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT1(PredFormatFunctor1(),
+ ++n1_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT1(PredFormatFunctor1(),
+ Bool(++n1_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(PredFormatFunction1,
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(PredFormatFunction1,
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(PredFormatFunctor1(),
+ n1_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT1 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT1Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(PredFormatFunctor1(),
+ Bool(n1_++));
+ finished_ = true;
+ }, "");
+}
+// Sample functions/functors for testing binary predicate assertions.
+
+// A binary predicate function.
+template <typename T1, typename T2>
+bool PredFunction2(T1 v1, T2 v2) {
+ return v1 + v2 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction2Int(int v1, int v2) {
+ return v1 + v2 > 0;
+}
+bool PredFunction2Bool(Bool v1, Bool v2) {
+ return v1 + v2 > 0;
+}
+
+// A binary predicate functor.
+struct PredFunctor2 {
+ template <typename T1, typename T2>
+ bool operator()(const T1& v1,
+ const T2& v2) {
+ return v1 + v2 > 0;
+ }
+};
+
+// A binary predicate-formatter function.
+template <typename T1, typename T2>
+testing::AssertionResult PredFormatFunction2(const char* e1,
+ const char* e2,
+ const T1& v1,
+ const T2& v2) {
+ if (PredFunction2(v1, v2))
+ return testing::AssertionSuccess();
+
+ testing::Message msg;
+ msg << e1 << " + " << e2
+ << " is expected to be positive, but evaluates to "
+ << v1 + v2 << ".";
+ return testing::AssertionFailure(msg);
+}
+
+// A binary predicate-formatter functor.
+struct PredFormatFunctor2 {
+ template <typename T1, typename T2>
+ testing::AssertionResult operator()(const char* e1,
+ const char* e2,
+ const T1& v1,
+ const T2& v2) const {
+ return PredFormatFunction2(e1, e2, v1, v2);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT2.
+
+class Predicate2Test : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = n2_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+ EXPECT_EQ(1, n2_) <<
+ "The predicate assertion didn't evaluate argument 3 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+ static int n2_;
+};
+
+bool Predicate2Test::expected_to_finish_;
+bool Predicate2Test::finished_;
+int Predicate2Test::n1_;
+int Predicate2Test::n2_;
+
+typedef Predicate2Test EXPECT_PRED_FORMAT2Test;
+typedef Predicate2Test ASSERT_PRED_FORMAT2Test;
+typedef Predicate2Test EXPECT_PRED2Test;
+typedef Predicate2Test ASSERT_PRED2Test;
+
+// Tests a successful EXPECT_PRED2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED2(PredFunction2Int,
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED2(PredFunction2Bool,
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED2(PredFunctor2(),
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED2(PredFunctor2(),
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED2Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(PredFunction2Int,
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED2Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(PredFunction2Bool,
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED2Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(PredFunctor2(),
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED2Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(PredFunctor2(),
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED2(PredFunction2Int,
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED2(PredFunction2Bool,
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED2(PredFunctor2(),
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED2(PredFunctor2(),
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED2Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED2(PredFunction2Int,
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED2Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED2(PredFunction2Bool,
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED2Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED2(PredFunctor2(),
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED2Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED2(PredFunctor2(),
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT2(PredFormatFunction2,
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT2(PredFormatFunction2,
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT2(PredFormatFunctor2(),
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT2(PredFormatFunctor2(),
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(PredFormatFunction2,
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(PredFormatFunction2,
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(PredFormatFunctor2(),
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(PredFormatFunctor2(),
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT2(PredFormatFunction2,
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT2(PredFormatFunction2,
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT2(PredFormatFunctor2(),
+ ++n1_,
+ ++n2_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT2(PredFormatFunctor2(),
+ Bool(++n1_),
+ Bool(++n2_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(PredFormatFunction2,
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(PredFormatFunction2,
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(PredFormatFunctor2(),
+ n1_++,
+ n2_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT2 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT2Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(PredFormatFunctor2(),
+ Bool(n1_++),
+ Bool(n2_++));
+ finished_ = true;
+ }, "");
+}
+// Sample functions/functors for testing ternary predicate assertions.
+
+// A ternary predicate function.
+template <typename T1, typename T2, typename T3>
+bool PredFunction3(T1 v1, T2 v2, T3 v3) {
+ return v1 + v2 + v3 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction3Int(int v1, int v2, int v3) {
+ return v1 + v2 + v3 > 0;
+}
+bool PredFunction3Bool(Bool v1, Bool v2, Bool v3) {
+ return v1 + v2 + v3 > 0;
+}
+
+// A ternary predicate functor.
+struct PredFunctor3 {
+ template <typename T1, typename T2, typename T3>
+ bool operator()(const T1& v1,
+ const T2& v2,
+ const T3& v3) {
+ return v1 + v2 + v3 > 0;
+ }
+};
+
+// A ternary predicate-formatter function.
+template <typename T1, typename T2, typename T3>
+testing::AssertionResult PredFormatFunction3(const char* e1,
+ const char* e2,
+ const char* e3,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3) {
+ if (PredFunction3(v1, v2, v3))
+ return testing::AssertionSuccess();
+
+ testing::Message msg;
+ msg << e1 << " + " << e2 << " + " << e3
+ << " is expected to be positive, but evaluates to "
+ << v1 + v2 + v3 << ".";
+ return testing::AssertionFailure(msg);
+}
+
+// A ternary predicate-formatter functor.
+struct PredFormatFunctor3 {
+ template <typename T1, typename T2, typename T3>
+ testing::AssertionResult operator()(const char* e1,
+ const char* e2,
+ const char* e3,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3) const {
+ return PredFormatFunction3(e1, e2, e3, v1, v2, v3);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT3.
+
+class Predicate3Test : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = n2_ = n3_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+ EXPECT_EQ(1, n2_) <<
+ "The predicate assertion didn't evaluate argument 3 "
+ "exactly once.";
+ EXPECT_EQ(1, n3_) <<
+ "The predicate assertion didn't evaluate argument 4 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+ static int n2_;
+ static int n3_;
+};
+
+bool Predicate3Test::expected_to_finish_;
+bool Predicate3Test::finished_;
+int Predicate3Test::n1_;
+int Predicate3Test::n2_;
+int Predicate3Test::n3_;
+
+typedef Predicate3Test EXPECT_PRED_FORMAT3Test;
+typedef Predicate3Test ASSERT_PRED_FORMAT3Test;
+typedef Predicate3Test EXPECT_PRED3Test;
+typedef Predicate3Test ASSERT_PRED3Test;
+
+// Tests a successful EXPECT_PRED3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED3(PredFunction3Int,
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED3(PredFunction3Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED3(PredFunctor3(),
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED3(PredFunctor3(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED3Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(PredFunction3Int,
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED3Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(PredFunction3Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED3Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(PredFunctor3(),
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED3Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(PredFunctor3(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED3(PredFunction3Int,
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED3(PredFunction3Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED3(PredFunctor3(),
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED3(PredFunctor3(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED3Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(PredFunction3Int,
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED3Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(PredFunction3Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED3Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(PredFunctor3(),
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED3Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(PredFunctor3(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT3(PredFormatFunction3,
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT3(PredFormatFunction3,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT3(PredFormatFunctor3(),
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT3(PredFormatFunctor3(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT3(PredFormatFunction3,
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT3(PredFormatFunction3,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT3(PredFormatFunctor3(),
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT3(PredFormatFunctor3(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT3(PredFormatFunction3,
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT3(PredFormatFunction3,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT3(PredFormatFunctor3(),
+ ++n1_,
+ ++n2_,
+ ++n3_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT3(PredFormatFunctor3(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT3(PredFormatFunction3,
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT3(PredFormatFunction3,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT3(PredFormatFunctor3(),
+ n1_++,
+ n2_++,
+ n3_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT3 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT3Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT3(PredFormatFunctor3(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++));
+ finished_ = true;
+ }, "");
+}
+// Sample functions/functors for testing 4-ary predicate assertions.
+
+// A 4-ary predicate function.
+template <typename T1, typename T2, typename T3, typename T4>
+bool PredFunction4(T1 v1, T2 v2, T3 v3, T4 v4) {
+ return v1 + v2 + v3 + v4 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction4Int(int v1, int v2, int v3, int v4) {
+ return v1 + v2 + v3 + v4 > 0;
+}
+bool PredFunction4Bool(Bool v1, Bool v2, Bool v3, Bool v4) {
+ return v1 + v2 + v3 + v4 > 0;
+}
+
+// A 4-ary predicate functor.
+struct PredFunctor4 {
+ template <typename T1, typename T2, typename T3, typename T4>
+ bool operator()(const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) {
+ return v1 + v2 + v3 + v4 > 0;
+ }
+};
+
+// A 4-ary predicate-formatter function.
+template <typename T1, typename T2, typename T3, typename T4>
+testing::AssertionResult PredFormatFunction4(const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) {
+ if (PredFunction4(v1, v2, v3, v4))
+ return testing::AssertionSuccess();
+
+ testing::Message msg;
+ msg << e1 << " + " << e2 << " + " << e3 << " + " << e4
+ << " is expected to be positive, but evaluates to "
+ << v1 + v2 + v3 + v4 << ".";
+ return testing::AssertionFailure(msg);
+}
+
+// A 4-ary predicate-formatter functor.
+struct PredFormatFunctor4 {
+ template <typename T1, typename T2, typename T3, typename T4>
+ testing::AssertionResult operator()(const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4) const {
+ return PredFormatFunction4(e1, e2, e3, e4, v1, v2, v3, v4);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT4.
+
+class Predicate4Test : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = n2_ = n3_ = n4_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+ EXPECT_EQ(1, n2_) <<
+ "The predicate assertion didn't evaluate argument 3 "
+ "exactly once.";
+ EXPECT_EQ(1, n3_) <<
+ "The predicate assertion didn't evaluate argument 4 "
+ "exactly once.";
+ EXPECT_EQ(1, n4_) <<
+ "The predicate assertion didn't evaluate argument 5 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+ static int n2_;
+ static int n3_;
+ static int n4_;
+};
+
+bool Predicate4Test::expected_to_finish_;
+bool Predicate4Test::finished_;
+int Predicate4Test::n1_;
+int Predicate4Test::n2_;
+int Predicate4Test::n3_;
+int Predicate4Test::n4_;
+
+typedef Predicate4Test EXPECT_PRED_FORMAT4Test;
+typedef Predicate4Test ASSERT_PRED_FORMAT4Test;
+typedef Predicate4Test EXPECT_PRED4Test;
+typedef Predicate4Test ASSERT_PRED4Test;
+
+// Tests a successful EXPECT_PRED4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED4(PredFunction4Int,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED4(PredFunction4Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED4(PredFunctor4(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED4(PredFunctor4(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED4Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED4(PredFunction4Int,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED4Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED4(PredFunction4Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED4Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED4(PredFunctor4(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED4Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED4(PredFunctor4(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED4(PredFunction4Int,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED4(PredFunction4Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED4(PredFunctor4(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED4(PredFunctor4(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED4Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED4(PredFunction4Int,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED4Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED4(PredFunction4Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED4Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED4(PredFunctor4(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED4Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED4(PredFunctor4(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT4(PredFormatFunction4,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT4(PredFormatFunction4,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT4(PredFormatFunctor4(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT4(PredFormatFunctor4(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(PredFormatFunction4,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(PredFormatFunction4,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(PredFormatFunctor4(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(PredFormatFunctor4(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT4(PredFormatFunction4,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT4(PredFormatFunction4,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT4(PredFormatFunctor4(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT4(PredFormatFunctor4(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT4(PredFormatFunction4,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT4(PredFormatFunction4,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT4(PredFormatFunctor4(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT4 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT4Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT4(PredFormatFunctor4(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++));
+ finished_ = true;
+ }, "");
+}
+// Sample functions/functors for testing 5-ary predicate assertions.
+
+// A 5-ary predicate function.
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+bool PredFunction5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) {
+ return v1 + v2 + v3 + v4 + v5 > 0;
+}
+
+// The following two functions are needed to circumvent a bug in
+// gcc 2.95.3, which sometimes has problem with the above template
+// function.
+bool PredFunction5Int(int v1, int v2, int v3, int v4, int v5) {
+ return v1 + v2 + v3 + v4 + v5 > 0;
+}
+bool PredFunction5Bool(Bool v1, Bool v2, Bool v3, Bool v4, Bool v5) {
+ return v1 + v2 + v3 + v4 + v5 > 0;
+}
+
+// A 5-ary predicate functor.
+struct PredFunctor5 {
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ bool operator()(const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) {
+ return v1 + v2 + v3 + v4 + v5 > 0;
+ }
+};
+
+// A 5-ary predicate-formatter function.
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+testing::AssertionResult PredFormatFunction5(const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) {
+ if (PredFunction5(v1, v2, v3, v4, v5))
+ return testing::AssertionSuccess();
+
+ testing::Message msg;
+ msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5
+ << " is expected to be positive, but evaluates to "
+ << v1 + v2 + v3 + v4 + v5 << ".";
+ return testing::AssertionFailure(msg);
+}
+
+// A 5-ary predicate-formatter functor.
+struct PredFormatFunctor5 {
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ testing::AssertionResult operator()(const char* e1,
+ const char* e2,
+ const char* e3,
+ const char* e4,
+ const char* e5,
+ const T1& v1,
+ const T2& v2,
+ const T3& v3,
+ const T4& v4,
+ const T5& v5) const {
+ return PredFormatFunction5(e1, e2, e3, e4, e5, v1, v2, v3, v4, v5);
+ }
+};
+
+// Tests for {EXPECT|ASSERT}_PRED_FORMAT5.
+
+class Predicate5Test : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ expected_to_finish_ = true;
+ finished_ = false;
+ n1_ = n2_ = n3_ = n4_ = n5_ = 0;
+ }
+
+ virtual void TearDown() {
+ // Verifies that each of the predicate's arguments was evaluated
+ // exactly once.
+ EXPECT_EQ(1, n1_) <<
+ "The predicate assertion didn't evaluate argument 2 "
+ "exactly once.";
+ EXPECT_EQ(1, n2_) <<
+ "The predicate assertion didn't evaluate argument 3 "
+ "exactly once.";
+ EXPECT_EQ(1, n3_) <<
+ "The predicate assertion didn't evaluate argument 4 "
+ "exactly once.";
+ EXPECT_EQ(1, n4_) <<
+ "The predicate assertion didn't evaluate argument 5 "
+ "exactly once.";
+ EXPECT_EQ(1, n5_) <<
+ "The predicate assertion didn't evaluate argument 6 "
+ "exactly once.";
+
+ // Verifies that the control flow in the test function is expected.
+ if (expected_to_finish_ && !finished_) {
+ FAIL() << "The predicate assertion unexpactedly aborted the test.";
+ } else if (!expected_to_finish_ && finished_) {
+ FAIL() << "The failed predicate assertion didn't abort the test "
+ "as expected.";
+ }
+ }
+
+ // true iff the test function is expected to run to finish.
+ static bool expected_to_finish_;
+
+ // true iff the test function did run to finish.
+ static bool finished_;
+
+ static int n1_;
+ static int n2_;
+ static int n3_;
+ static int n4_;
+ static int n5_;
+};
+
+bool Predicate5Test::expected_to_finish_;
+bool Predicate5Test::finished_;
+int Predicate5Test::n1_;
+int Predicate5Test::n2_;
+int Predicate5Test::n3_;
+int Predicate5Test::n4_;
+int Predicate5Test::n5_;
+
+typedef Predicate5Test EXPECT_PRED_FORMAT5Test;
+typedef Predicate5Test ASSERT_PRED_FORMAT5Test;
+typedef Predicate5Test EXPECT_PRED5Test;
+typedef Predicate5Test ASSERT_PRED5Test;
+
+// Tests a successful EXPECT_PRED5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED5(PredFunction5Int,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED5(PredFunction5Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED5(PredFunctor5(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED5(PredFunctor5(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED5Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED5(PredFunction5Int,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED5Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED5(PredFunction5Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED5Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED5(PredFunctor5(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED5Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED5(PredFunctor5(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED5(PredFunction5Int,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED5(PredFunction5Bool,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED5(PredFunctor5(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED5(PredFunctor5(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED5Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED5(PredFunction5Int,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED5Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED5(PredFunction5Bool,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED5Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED5(PredFunctor5(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED5Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED5(PredFunctor5(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT5(PredFormatFunction5,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT5(PredFormatFunction5,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) {
+ EXPECT_PRED_FORMAT5(PredFormatFunctor5(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) {
+ EXPECT_PRED_FORMAT5(PredFormatFunctor5(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a failed EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT5(PredFormatFunction5,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT5(PredFormatFunction5,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT5(PredFormatFunctor5(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed EXPECT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(EXPECT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) {
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT5(PredFormatFunctor5(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a successful ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT5(PredFormatFunction5,
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT5(PredFormatFunction5,
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeSuccess) {
+ ASSERT_PRED_FORMAT5(PredFormatFunctor5(),
+ ++n1_,
+ ++n2_,
+ ++n3_,
+ ++n4_,
+ ++n5_);
+ finished_ = true;
+}
+
+// Tests a successful ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeSuccess) {
+ ASSERT_PRED_FORMAT5(PredFormatFunctor5(),
+ Bool(++n1_),
+ Bool(++n2_),
+ Bool(++n3_),
+ Bool(++n4_),
+ Bool(++n5_));
+ finished_ = true;
+}
+
+// Tests a failed ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(PredFormatFunction5,
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a function on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctionOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(PredFormatFunction5,
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a built-in type (int).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnBuiltInTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(PredFormatFunctor5(),
+ n1_++,
+ n2_++,
+ n3_++,
+ n4_++,
+ n5_++);
+ finished_ = true;
+ }, "");
+}
+
+// Tests a failed ASSERT_PRED_FORMAT5 where the
+// predicate-formatter is a functor on a user-defined type (Bool).
+TEST_F(ASSERT_PRED_FORMAT5Test, FunctorOnUserTypeFailure) {
+ expected_to_finish_ = false;
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(PredFormatFunctor5(),
+ Bool(n1_++),
+ Bool(n2_++),
+ Bool(n3_++),
+ Bool(n4_++),
+ Bool(n5_++));
+ finished_ = true;
+ }, "");
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_prod_test.cc b/Source/ThirdParty/gtest/test/gtest_prod_test.cc
new file mode 100644
index 000000000..bc3201d0f
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_prod_test.cc
@@ -0,0 +1,57 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Unit test for include/gtest/gtest_prod.h.
+
+#include <gtest/gtest.h>
+#include "test/production.h"
+
+// Tests that private members can be accessed from a TEST declared as
+// a friend of the class.
+TEST(PrivateCodeTest, CanAccessPrivateMembers) {
+ PrivateCode a;
+ EXPECT_EQ(0, a.x_);
+
+ a.set_x(1);
+ EXPECT_EQ(1, a.x_);
+}
+
+typedef testing::Test PrivateCodeFixtureTest;
+
+// Tests that private members can be accessed from a TEST_F declared
+// as a friend of the class.
+TEST_F(PrivateCodeFixtureTest, CanAccessPrivateMembers) {
+ PrivateCode a;
+ EXPECT_EQ(0, a.x_);
+
+ a.set_x(2);
+ EXPECT_EQ(2, a.x_);
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_repeat_test.cc b/Source/ThirdParty/gtest/test/gtest_repeat_test.cc
new file mode 100644
index 000000000..df6868b83
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_repeat_test.cc
@@ -0,0 +1,253 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Tests the --gtest_repeat=number flag.
+
+#include <stdlib.h>
+#include <iostream>
+#include <gtest/gtest.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+namespace testing {
+
+GTEST_DECLARE_string_(death_test_style);
+GTEST_DECLARE_string_(filter);
+GTEST_DECLARE_int32_(repeat);
+
+} // namespace testing
+
+using testing::GTEST_FLAG(death_test_style);
+using testing::GTEST_FLAG(filter);
+using testing::GTEST_FLAG(repeat);
+
+namespace {
+
+// We need this when we are testing Google Test itself and therefore
+// cannot use Google Test assertions.
+#define GTEST_CHECK_INT_EQ_(expected, actual) \
+ do {\
+ const int expected_val = (expected);\
+ const int actual_val = (actual);\
+ if (::testing::internal::IsTrue(expected_val != actual_val)) {\
+ ::std::cout << "Value of: " #actual "\n"\
+ << " Actual: " << actual_val << "\n"\
+ << "Expected: " #expected "\n"\
+ << "Which is: " << expected_val << "\n";\
+ abort();\
+ }\
+ } while(::testing::internal::AlwaysFalse())
+
+
+// Used for verifying that global environment set-up and tear-down are
+// inside the gtest_repeat loop.
+
+int g_environment_set_up_count = 0;
+int g_environment_tear_down_count = 0;
+
+class MyEnvironment : public testing::Environment {
+ public:
+ MyEnvironment() {}
+ virtual void SetUp() { g_environment_set_up_count++; }
+ virtual void TearDown() { g_environment_tear_down_count++; }
+};
+
+// A test that should fail.
+
+int g_should_fail_count = 0;
+
+TEST(FooTest, ShouldFail) {
+ g_should_fail_count++;
+ EXPECT_EQ(0, 1) << "Expected failure.";
+}
+
+// A test that should pass.
+
+int g_should_pass_count = 0;
+
+TEST(FooTest, ShouldPass) {
+ g_should_pass_count++;
+}
+
+// A test that contains a thread-safe death test and a fast death
+// test. It should pass.
+
+int g_death_test_count = 0;
+
+TEST(BarDeathTest, ThreadSafeAndFast) {
+ g_death_test_count++;
+
+ GTEST_FLAG(death_test_style) = "threadsafe";
+ EXPECT_DEATH_IF_SUPPORTED(abort(), "");
+
+ GTEST_FLAG(death_test_style) = "fast";
+ EXPECT_DEATH_IF_SUPPORTED(abort(), "");
+}
+
+#if GTEST_HAS_PARAM_TEST
+int g_param_test_count = 0;
+
+const int kNumberOfParamTests = 10;
+
+class MyParamTest : public testing::TestWithParam<int> {};
+
+TEST_P(MyParamTest, ShouldPass) {
+ // TODO(vladl@google.com): Make parameter value checking robust
+ // WRT order of tests.
+ GTEST_CHECK_INT_EQ_(g_param_test_count % kNumberOfParamTests, GetParam());
+ g_param_test_count++;
+}
+INSTANTIATE_TEST_CASE_P(MyParamSequence,
+ MyParamTest,
+ testing::Range(0, kNumberOfParamTests));
+#endif // GTEST_HAS_PARAM_TEST
+
+// Resets the count for each test.
+void ResetCounts() {
+ g_environment_set_up_count = 0;
+ g_environment_tear_down_count = 0;
+ g_should_fail_count = 0;
+ g_should_pass_count = 0;
+ g_death_test_count = 0;
+#if GTEST_HAS_PARAM_TEST
+ g_param_test_count = 0;
+#endif // GTEST_HAS_PARAM_TEST
+}
+
+// Checks that the count for each test is expected.
+void CheckCounts(int expected) {
+ GTEST_CHECK_INT_EQ_(expected, g_environment_set_up_count);
+ GTEST_CHECK_INT_EQ_(expected, g_environment_tear_down_count);
+ GTEST_CHECK_INT_EQ_(expected, g_should_fail_count);
+ GTEST_CHECK_INT_EQ_(expected, g_should_pass_count);
+ GTEST_CHECK_INT_EQ_(expected, g_death_test_count);
+#if GTEST_HAS_PARAM_TEST
+ GTEST_CHECK_INT_EQ_(expected * kNumberOfParamTests, g_param_test_count);
+#endif // GTEST_HAS_PARAM_TEST
+}
+
+// Tests the behavior of Google Test when --gtest_repeat is not specified.
+void TestRepeatUnspecified() {
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS());
+ CheckCounts(1);
+}
+
+// Tests the behavior of Google Test when --gtest_repeat has the given value.
+void TestRepeat(int repeat) {
+ GTEST_FLAG(repeat) = repeat;
+
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(repeat > 0 ? 1 : 0, RUN_ALL_TESTS());
+ CheckCounts(repeat);
+}
+
+// Tests using --gtest_repeat when --gtest_filter specifies an empty
+// set of tests.
+void TestRepeatWithEmptyFilter(int repeat) {
+ GTEST_FLAG(repeat) = repeat;
+ GTEST_FLAG(filter) = "None";
+
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS());
+ CheckCounts(0);
+}
+
+// Tests using --gtest_repeat when --gtest_filter specifies a set of
+// successful tests.
+void TestRepeatWithFilterForSuccessfulTests(int repeat) {
+ GTEST_FLAG(repeat) = repeat;
+ GTEST_FLAG(filter) = "*-*ShouldFail";
+
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(0, RUN_ALL_TESTS());
+ GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count);
+ GTEST_CHECK_INT_EQ_(0, g_should_fail_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_should_pass_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_death_test_count);
+#if GTEST_HAS_PARAM_TEST
+ GTEST_CHECK_INT_EQ_(repeat * kNumberOfParamTests, g_param_test_count);
+#endif // GTEST_HAS_PARAM_TEST
+}
+
+// Tests using --gtest_repeat when --gtest_filter specifies a set of
+// failed tests.
+void TestRepeatWithFilterForFailedTests(int repeat) {
+ GTEST_FLAG(repeat) = repeat;
+ GTEST_FLAG(filter) = "*ShouldFail";
+
+ ResetCounts();
+ GTEST_CHECK_INT_EQ_(1, RUN_ALL_TESTS());
+ GTEST_CHECK_INT_EQ_(repeat, g_environment_set_up_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_environment_tear_down_count);
+ GTEST_CHECK_INT_EQ_(repeat, g_should_fail_count);
+ GTEST_CHECK_INT_EQ_(0, g_should_pass_count);
+ GTEST_CHECK_INT_EQ_(0, g_death_test_count);
+#if GTEST_HAS_PARAM_TEST
+ GTEST_CHECK_INT_EQ_(0, g_param_test_count);
+#endif // GTEST_HAS_PARAM_TEST
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ testing::AddGlobalTestEnvironment(new MyEnvironment);
+
+ TestRepeatUnspecified();
+ TestRepeat(0);
+ TestRepeat(1);
+ TestRepeat(5);
+
+ TestRepeatWithEmptyFilter(2);
+ TestRepeatWithEmptyFilter(3);
+
+ TestRepeatWithFilterForSuccessfulTests(3);
+
+ TestRepeatWithFilterForFailedTests(4);
+
+ // It would be nice to verify that the tests indeed loop forever
+ // when GTEST_FLAG(repeat) is negative, but this test will be quite
+ // complicated to write. Since this flag is for interactive
+ // debugging only and doesn't affect the normal test result, such a
+ // test would be an overkill.
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_shuffle_test.py b/Source/ThirdParty/gtest/test/gtest_shuffle_test.py
new file mode 100755
index 000000000..30d0303d1
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_shuffle_test.py
@@ -0,0 +1,325 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 Google Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Verifies that test shuffling works."""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import gtest_test_utils
+
+# Command to run the gtest_shuffle_test_ program.
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_shuffle_test_')
+
+# The environment variables for test sharding.
+TOTAL_SHARDS_ENV_VAR = 'GTEST_TOTAL_SHARDS'
+SHARD_INDEX_ENV_VAR = 'GTEST_SHARD_INDEX'
+
+TEST_FILTER = 'A*.A:A*.B:C*'
+
+ALL_TESTS = []
+ACTIVE_TESTS = []
+FILTERED_TESTS = []
+SHARDED_TESTS = []
+
+SHUFFLED_ALL_TESTS = []
+SHUFFLED_ACTIVE_TESTS = []
+SHUFFLED_FILTERED_TESTS = []
+SHUFFLED_SHARDED_TESTS = []
+
+
+def AlsoRunDisabledTestsFlag():
+ return '--gtest_also_run_disabled_tests'
+
+
+def FilterFlag(test_filter):
+ return '--gtest_filter=%s' % (test_filter,)
+
+
+def RepeatFlag(n):
+ return '--gtest_repeat=%s' % (n,)
+
+
+def ShuffleFlag():
+ return '--gtest_shuffle'
+
+
+def RandomSeedFlag(n):
+ return '--gtest_random_seed=%s' % (n,)
+
+
+def RunAndReturnOutput(extra_env, args):
+ """Runs the test program and returns its output."""
+
+ environ_copy = os.environ.copy()
+ environ_copy.update(extra_env)
+
+ return gtest_test_utils.Subprocess([COMMAND] + args, env=environ_copy).output
+
+
+def GetTestsForAllIterations(extra_env, args):
+ """Runs the test program and returns a list of test lists.
+
+ Args:
+ extra_env: a map from environment variables to their values
+ args: command line flags to pass to gtest_shuffle_test_
+
+ Returns:
+ A list where the i-th element is the list of tests run in the i-th
+ test iteration.
+ """
+
+ test_iterations = []
+ for line in RunAndReturnOutput(extra_env, args).split('\n'):
+ if line.startswith('----'):
+ tests = []
+ test_iterations.append(tests)
+ elif line.strip():
+ tests.append(line.strip()) # 'TestCaseName.TestName'
+
+ return test_iterations
+
+
+def GetTestCases(tests):
+ """Returns a list of test cases in the given full test names.
+
+ Args:
+ tests: a list of full test names
+
+ Returns:
+ A list of test cases from 'tests', in their original order.
+ Consecutive duplicates are removed.
+ """
+
+ test_cases = []
+ for test in tests:
+ test_case = test.split('.')[0]
+ if not test_case in test_cases:
+ test_cases.append(test_case)
+
+ return test_cases
+
+
+def CalculateTestLists():
+ """Calculates the list of tests run under different flags."""
+
+ if not ALL_TESTS:
+ ALL_TESTS.extend(
+ GetTestsForAllIterations({}, [AlsoRunDisabledTestsFlag()])[0])
+
+ if not ACTIVE_TESTS:
+ ACTIVE_TESTS.extend(GetTestsForAllIterations({}, [])[0])
+
+ if not FILTERED_TESTS:
+ FILTERED_TESTS.extend(
+ GetTestsForAllIterations({}, [FilterFlag(TEST_FILTER)])[0])
+
+ if not SHARDED_TESTS:
+ SHARDED_TESTS.extend(
+ GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '1'},
+ [])[0])
+
+ if not SHUFFLED_ALL_TESTS:
+ SHUFFLED_ALL_TESTS.extend(GetTestsForAllIterations(
+ {}, [AlsoRunDisabledTestsFlag(), ShuffleFlag(), RandomSeedFlag(1)])[0])
+
+ if not SHUFFLED_ACTIVE_TESTS:
+ SHUFFLED_ACTIVE_TESTS.extend(GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1)])[0])
+
+ if not SHUFFLED_FILTERED_TESTS:
+ SHUFFLED_FILTERED_TESTS.extend(GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1), FilterFlag(TEST_FILTER)])[0])
+
+ if not SHUFFLED_SHARDED_TESTS:
+ SHUFFLED_SHARDED_TESTS.extend(
+ GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '1'},
+ [ShuffleFlag(), RandomSeedFlag(1)])[0])
+
+
+class GTestShuffleUnitTest(gtest_test_utils.TestCase):
+ """Tests test shuffling."""
+
+ def setUp(self):
+ CalculateTestLists()
+
+ def testShufflePreservesNumberOfTests(self):
+ self.assertEqual(len(ALL_TESTS), len(SHUFFLED_ALL_TESTS))
+ self.assertEqual(len(ACTIVE_TESTS), len(SHUFFLED_ACTIVE_TESTS))
+ self.assertEqual(len(FILTERED_TESTS), len(SHUFFLED_FILTERED_TESTS))
+ self.assertEqual(len(SHARDED_TESTS), len(SHUFFLED_SHARDED_TESTS))
+
+ def testShuffleChangesTestOrder(self):
+ self.assert_(SHUFFLED_ALL_TESTS != ALL_TESTS, SHUFFLED_ALL_TESTS)
+ self.assert_(SHUFFLED_ACTIVE_TESTS != ACTIVE_TESTS, SHUFFLED_ACTIVE_TESTS)
+ self.assert_(SHUFFLED_FILTERED_TESTS != FILTERED_TESTS,
+ SHUFFLED_FILTERED_TESTS)
+ self.assert_(SHUFFLED_SHARDED_TESTS != SHARDED_TESTS,
+ SHUFFLED_SHARDED_TESTS)
+
+ def testShuffleChangesTestCaseOrder(self):
+ self.assert_(GetTestCases(SHUFFLED_ALL_TESTS) != GetTestCases(ALL_TESTS),
+ GetTestCases(SHUFFLED_ALL_TESTS))
+ self.assert_(
+ GetTestCases(SHUFFLED_ACTIVE_TESTS) != GetTestCases(ACTIVE_TESTS),
+ GetTestCases(SHUFFLED_ACTIVE_TESTS))
+ self.assert_(
+ GetTestCases(SHUFFLED_FILTERED_TESTS) != GetTestCases(FILTERED_TESTS),
+ GetTestCases(SHUFFLED_FILTERED_TESTS))
+ self.assert_(
+ GetTestCases(SHUFFLED_SHARDED_TESTS) != GetTestCases(SHARDED_TESTS),
+ GetTestCases(SHUFFLED_SHARDED_TESTS))
+
+ def testShuffleDoesNotRepeatTest(self):
+ for test in SHUFFLED_ALL_TESTS:
+ self.assertEqual(1, SHUFFLED_ALL_TESTS.count(test),
+ '%s appears more than once' % (test,))
+ for test in SHUFFLED_ACTIVE_TESTS:
+ self.assertEqual(1, SHUFFLED_ACTIVE_TESTS.count(test),
+ '%s appears more than once' % (test,))
+ for test in SHUFFLED_FILTERED_TESTS:
+ self.assertEqual(1, SHUFFLED_FILTERED_TESTS.count(test),
+ '%s appears more than once' % (test,))
+ for test in SHUFFLED_SHARDED_TESTS:
+ self.assertEqual(1, SHUFFLED_SHARDED_TESTS.count(test),
+ '%s appears more than once' % (test,))
+
+ def testShuffleDoesNotCreateNewTest(self):
+ for test in SHUFFLED_ALL_TESTS:
+ self.assert_(test in ALL_TESTS, '%s is an invalid test' % (test,))
+ for test in SHUFFLED_ACTIVE_TESTS:
+ self.assert_(test in ACTIVE_TESTS, '%s is an invalid test' % (test,))
+ for test in SHUFFLED_FILTERED_TESTS:
+ self.assert_(test in FILTERED_TESTS, '%s is an invalid test' % (test,))
+ for test in SHUFFLED_SHARDED_TESTS:
+ self.assert_(test in SHARDED_TESTS, '%s is an invalid test' % (test,))
+
+ def testShuffleIncludesAllTests(self):
+ for test in ALL_TESTS:
+ self.assert_(test in SHUFFLED_ALL_TESTS, '%s is missing' % (test,))
+ for test in ACTIVE_TESTS:
+ self.assert_(test in SHUFFLED_ACTIVE_TESTS, '%s is missing' % (test,))
+ for test in FILTERED_TESTS:
+ self.assert_(test in SHUFFLED_FILTERED_TESTS, '%s is missing' % (test,))
+ for test in SHARDED_TESTS:
+ self.assert_(test in SHUFFLED_SHARDED_TESTS, '%s is missing' % (test,))
+
+ def testShuffleLeavesDeathTestsAtFront(self):
+ non_death_test_found = False
+ for test in SHUFFLED_ACTIVE_TESTS:
+ if 'DeathTest.' in test:
+ self.assert_(not non_death_test_found,
+ '%s appears after a non-death test' % (test,))
+ else:
+ non_death_test_found = True
+
+ def _VerifyTestCasesDoNotInterleave(self, tests):
+ test_cases = []
+ for test in tests:
+ [test_case, _] = test.split('.')
+ if test_cases and test_cases[-1] != test_case:
+ test_cases.append(test_case)
+ self.assertEqual(1, test_cases.count(test_case),
+ 'Test case %s is not grouped together in %s' %
+ (test_case, tests))
+
+ def testShuffleDoesNotInterleaveTestCases(self):
+ self._VerifyTestCasesDoNotInterleave(SHUFFLED_ALL_TESTS)
+ self._VerifyTestCasesDoNotInterleave(SHUFFLED_ACTIVE_TESTS)
+ self._VerifyTestCasesDoNotInterleave(SHUFFLED_FILTERED_TESTS)
+ self._VerifyTestCasesDoNotInterleave(SHUFFLED_SHARDED_TESTS)
+
+ def testShuffleRestoresOrderAfterEachIteration(self):
+ # Get the test lists in all 3 iterations, using random seed 1, 2,
+ # and 3 respectively. Google Test picks a different seed in each
+ # iteration, and this test depends on the current implementation
+ # picking successive numbers. This dependency is not ideal, but
+ # makes the test much easier to write.
+ [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = (
+ GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
+
+ # Make sure running the tests with random seed 1 gets the same
+ # order as in iteration 1 above.
+ [tests_with_seed1] = GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1)])
+ self.assertEqual(tests_in_iteration1, tests_with_seed1)
+
+ # Make sure running the tests with random seed 2 gets the same
+ # order as in iteration 2 above. Success means that Google Test
+ # correctly restores the test order before re-shuffling at the
+ # beginning of iteration 2.
+ [tests_with_seed2] = GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(2)])
+ self.assertEqual(tests_in_iteration2, tests_with_seed2)
+
+ # Make sure running the tests with random seed 3 gets the same
+ # order as in iteration 3 above. Success means that Google Test
+ # correctly restores the test order before re-shuffling at the
+ # beginning of iteration 3.
+ [tests_with_seed3] = GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(3)])
+ self.assertEqual(tests_in_iteration3, tests_with_seed3)
+
+ def testShuffleGeneratesNewOrderInEachIteration(self):
+ [tests_in_iteration1, tests_in_iteration2, tests_in_iteration3] = (
+ GetTestsForAllIterations(
+ {}, [ShuffleFlag(), RandomSeedFlag(1), RepeatFlag(3)]))
+
+ self.assert_(tests_in_iteration1 != tests_in_iteration2,
+ tests_in_iteration1)
+ self.assert_(tests_in_iteration1 != tests_in_iteration3,
+ tests_in_iteration1)
+ self.assert_(tests_in_iteration2 != tests_in_iteration3,
+ tests_in_iteration2)
+
+ def testShuffleShardedTestsPreservesPartition(self):
+ # If we run M tests on N shards, the same M tests should be run in
+ # total, regardless of the random seeds used by the shards.
+ [tests1] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '0'},
+ [ShuffleFlag(), RandomSeedFlag(1)])
+ [tests2] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '1'},
+ [ShuffleFlag(), RandomSeedFlag(20)])
+ [tests3] = GetTestsForAllIterations({TOTAL_SHARDS_ENV_VAR: '3',
+ SHARD_INDEX_ENV_VAR: '2'},
+ [ShuffleFlag(), RandomSeedFlag(25)])
+ sorted_sharded_tests = tests1 + tests2 + tests3
+ sorted_sharded_tests.sort()
+ sorted_active_tests = []
+ sorted_active_tests.extend(ACTIVE_TESTS)
+ sorted_active_tests.sort()
+ self.assertEqual(sorted_active_tests, sorted_sharded_tests)
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_shuffle_test_.cc b/Source/ThirdParty/gtest/test/gtest_shuffle_test_.cc
new file mode 100644
index 000000000..53ecf7770
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_shuffle_test_.cc
@@ -0,0 +1,104 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Verifies that test shuffling works.
+
+#include <gtest/gtest.h>
+
+namespace {
+
+using ::testing::EmptyTestEventListener;
+using ::testing::InitGoogleTest;
+using ::testing::Message;
+using ::testing::Test;
+using ::testing::TestEventListeners;
+using ::testing::TestInfo;
+using ::testing::UnitTest;
+using ::testing::internal::String;
+using ::testing::internal::scoped_ptr;
+
+// The test methods are empty, as the sole purpose of this program is
+// to print the test names before/after shuffling.
+
+class A : public Test {};
+TEST_F(A, A) {}
+TEST_F(A, B) {}
+
+TEST(ADeathTest, A) {}
+TEST(ADeathTest, B) {}
+TEST(ADeathTest, C) {}
+
+TEST(B, A) {}
+TEST(B, B) {}
+TEST(B, C) {}
+TEST(B, DISABLED_D) {}
+TEST(B, DISABLED_E) {}
+
+TEST(BDeathTest, A) {}
+TEST(BDeathTest, B) {}
+
+TEST(C, A) {}
+TEST(C, B) {}
+TEST(C, C) {}
+TEST(C, DISABLED_D) {}
+
+TEST(CDeathTest, A) {}
+
+TEST(DISABLED_D, A) {}
+TEST(DISABLED_D, DISABLED_B) {}
+
+// This printer prints the full test names only, starting each test
+// iteration with a "----" marker.
+class TestNamePrinter : public EmptyTestEventListener {
+ public:
+ virtual void OnTestIterationStart(const UnitTest& /* unit_test */,
+ int /* iteration */) {
+ printf("----\n");
+ }
+
+ virtual void OnTestStart(const TestInfo& test_info) {
+ printf("%s.%s\n", test_info.test_case_name(), test_info.name());
+ }
+};
+
+} // namespace
+
+int main(int argc, char **argv) {
+ InitGoogleTest(&argc, argv);
+
+ // Replaces the default printer with TestNamePrinter, which prints
+ // the test name only.
+ TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_result_printer());
+ listeners.Append(new TestNamePrinter);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_sole_header_test.cc b/Source/ThirdParty/gtest/test/gtest_sole_header_test.cc
new file mode 100644
index 000000000..de91e800f
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_sole_header_test.cc
@@ -0,0 +1,57 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: mheule@google.com (Markus Heule)
+//
+// This test verifies that it's possible to use Google Test by including
+// the gtest.h header file alone.
+
+#include <gtest/gtest.h>
+
+namespace {
+
+void Subroutine() {
+ EXPECT_EQ(42, 42);
+}
+
+TEST(NoFatalFailureTest, ExpectNoFatalFailure) {
+ EXPECT_NO_FATAL_FAILURE(;);
+ EXPECT_NO_FATAL_FAILURE(SUCCEED());
+ EXPECT_NO_FATAL_FAILURE(Subroutine());
+ EXPECT_NO_FATAL_FAILURE({ SUCCEED(); });
+}
+
+TEST(NoFatalFailureTest, AssertNoFatalFailure) {
+ ASSERT_NO_FATAL_FAILURE(;);
+ ASSERT_NO_FATAL_FAILURE(SUCCEED());
+ ASSERT_NO_FATAL_FAILURE(Subroutine());
+ ASSERT_NO_FATAL_FAILURE({ SUCCEED(); });
+}
+
+} // namespace
diff --git a/Source/ThirdParty/gtest/test/gtest_stress_test.cc b/Source/ThirdParty/gtest/test/gtest_stress_test.cc
new file mode 100644
index 000000000..f5af78cc6
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_stress_test.cc
@@ -0,0 +1,257 @@
+// Copyright 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Tests that SCOPED_TRACE() and various Google Test assertions can be
+// used in a large number of threads concurrently.
+
+#include <gtest/gtest.h>
+
+#include <iostream>
+#include <vector>
+
+// We must define this macro in order to #include
+// gtest-internal-inl.h. This is how Google Test prevents a user from
+// accidentally depending on its internal implementation.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#if GTEST_IS_THREADSAFE
+
+namespace testing {
+namespace {
+
+using internal::Notification;
+using internal::String;
+using internal::TestPropertyKeyIs;
+using internal::ThreadWithParam;
+using internal::scoped_ptr;
+
+// In order to run tests in this file, for platforms where Google Test is
+// thread safe, implement ThreadWithParam. See the description of its API
+// in gtest-port.h, where it is defined for already supported platforms.
+
+// How many threads to create?
+const int kThreadCount = 50;
+
+String IdToKey(int id, const char* suffix) {
+ Message key;
+ key << "key_" << id << "_" << suffix;
+ return key.GetString();
+}
+
+String IdToString(int id) {
+ Message id_message;
+ id_message << id;
+ return id_message.GetString();
+}
+
+void ExpectKeyAndValueWereRecordedForId(
+ const std::vector<TestProperty>& properties,
+ int id, const char* suffix) {
+ TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str());
+ const std::vector<TestProperty>::const_iterator property =
+ std::find_if(properties.begin(), properties.end(), matches_key);
+ ASSERT_TRUE(property != properties.end())
+ << "expecting " << suffix << " value for id " << id;
+ EXPECT_STREQ(IdToString(id).c_str(), property->value());
+}
+
+// Calls a large number of Google Test assertions, where exactly one of them
+// will fail.
+void ManyAsserts(int id) {
+ GTEST_LOG_(INFO) << "Thread #" << id << " running...";
+
+ SCOPED_TRACE(Message() << "Thread #" << id);
+
+ for (int i = 0; i < kThreadCount; i++) {
+ SCOPED_TRACE(Message() << "Iteration #" << i);
+
+ // A bunch of assertions that should succeed.
+ EXPECT_TRUE(true);
+ ASSERT_FALSE(false) << "This shouldn't fail.";
+ EXPECT_STREQ("a", "a");
+ ASSERT_LE(5, 6);
+ EXPECT_EQ(i, i) << "This shouldn't fail.";
+
+ // RecordProperty() should interact safely with other threads as well.
+ // The shared_key forces property updates.
+ Test::RecordProperty(IdToKey(id, "string").c_str(), IdToString(id).c_str());
+ Test::RecordProperty(IdToKey(id, "int").c_str(), id);
+ Test::RecordProperty("shared_key", IdToString(id).c_str());
+
+ // This assertion should fail kThreadCount times per thread. It
+ // is for testing whether Google Test can handle failed assertions in a
+ // multi-threaded context.
+ EXPECT_LT(i, 0) << "This should always fail.";
+ }
+}
+
+void CheckTestFailureCount(int expected_failures) {
+ const TestInfo* const info = UnitTest::GetInstance()->current_test_info();
+ const TestResult* const result = info->result();
+ GTEST_CHECK_(expected_failures == result->total_part_count())
+ << "Logged " << result->total_part_count() << " failures "
+ << " vs. " << expected_failures << " expected";
+}
+
+// Tests using SCOPED_TRACE() and Google Test assertions in many threads
+// concurrently.
+TEST(StressTest, CanUseScopedTraceAndAssertionsInManyThreads) {
+ {
+ scoped_ptr<ThreadWithParam<int> > threads[kThreadCount];
+ Notification threads_can_start;
+ for (int i = 0; i != kThreadCount; i++)
+ threads[i].reset(new ThreadWithParam<int>(&ManyAsserts,
+ i,
+ &threads_can_start));
+
+ threads_can_start.Notify();
+
+ // Blocks until all the threads are done.
+ for (int i = 0; i != kThreadCount; i++)
+ threads[i]->Join();
+ }
+
+ // Ensures that kThreadCount*kThreadCount failures have been reported.
+ const TestInfo* const info = UnitTest::GetInstance()->current_test_info();
+ const TestResult* const result = info->result();
+
+ std::vector<TestProperty> properties;
+ // We have no access to the TestResult's list of properties but we can
+ // copy them one by one.
+ for (int i = 0; i < result->test_property_count(); ++i)
+ properties.push_back(result->GetTestProperty(i));
+
+ EXPECT_EQ(kThreadCount * 2 + 1, result->test_property_count())
+ << "String and int values recorded on each thread, "
+ << "as well as one shared_key";
+ for (int i = 0; i < kThreadCount; ++i) {
+ ExpectKeyAndValueWereRecordedForId(properties, i, "string");
+ ExpectKeyAndValueWereRecordedForId(properties, i, "int");
+ }
+ CheckTestFailureCount(kThreadCount*kThreadCount);
+}
+
+void FailingThread(bool is_fatal) {
+ if (is_fatal)
+ FAIL() << "Fatal failure in some other thread. "
+ << "(This failure is expected.)";
+ else
+ ADD_FAILURE() << "Non-fatal failure in some other thread. "
+ << "(This failure is expected.)";
+}
+
+void GenerateFatalFailureInAnotherThread(bool is_fatal) {
+ ThreadWithParam<bool> thread(&FailingThread, is_fatal, NULL);
+ thread.Join();
+}
+
+TEST(NoFatalFailureTest, ExpectNoFatalFailureIgnoresFailuresInOtherThreads) {
+ EXPECT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true));
+ // We should only have one failure (the one from
+ // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE
+ // should succeed.
+ CheckTestFailureCount(1);
+}
+
+void AssertNoFatalFailureIgnoresFailuresInOtherThreads() {
+ ASSERT_NO_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true));
+}
+TEST(NoFatalFailureTest, AssertNoFatalFailureIgnoresFailuresInOtherThreads) {
+ // Using a subroutine, to make sure, that the test continues.
+ AssertNoFatalFailureIgnoresFailuresInOtherThreads();
+ // We should only have one failure (the one from
+ // GenerateFatalFailureInAnotherThread()), since the EXPECT_NO_FATAL_FAILURE
+ // should succeed.
+ CheckTestFailureCount(1);
+}
+
+TEST(FatalFailureTest, ExpectFatalFailureIgnoresFailuresInOtherThreads) {
+ // This statement should fail, since the current thread doesn't generate a
+ // fatal failure, only another one does.
+ EXPECT_FATAL_FAILURE(GenerateFatalFailureInAnotherThread(true), "expected");
+ CheckTestFailureCount(2);
+}
+
+TEST(FatalFailureOnAllThreadsTest, ExpectFatalFailureOnAllThreads) {
+ // This statement should succeed, because failures in all threads are
+ // considered.
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(
+ GenerateFatalFailureInAnotherThread(true), "expected");
+ CheckTestFailureCount(0);
+ // We need to add a failure, because main() checks that there are failures.
+ // But when only this test is run, we shouldn't have any failures.
+ ADD_FAILURE() << "This is an expected non-fatal failure.";
+}
+
+TEST(NonFatalFailureTest, ExpectNonFatalFailureIgnoresFailuresInOtherThreads) {
+ // This statement should fail, since the current thread doesn't generate a
+ // fatal failure, only another one does.
+ EXPECT_NONFATAL_FAILURE(GenerateFatalFailureInAnotherThread(false),
+ "expected");
+ CheckTestFailureCount(2);
+}
+
+TEST(NonFatalFailureOnAllThreadsTest, ExpectNonFatalFailureOnAllThreads) {
+ // This statement should succeed, because failures in all threads are
+ // considered.
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(
+ GenerateFatalFailureInAnotherThread(false), "expected");
+ CheckTestFailureCount(0);
+ // We need to add a failure, because main() checks that there are failures,
+ // But when only this test is run, we shouldn't have any failures.
+ ADD_FAILURE() << "This is an expected non-fatal failure.";
+}
+
+} // namespace
+} // namespace testing
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+
+ const int result = RUN_ALL_TESTS(); // Expected to fail.
+ GTEST_CHECK_(result == 1) << "RUN_ALL_TESTS() did not fail as expected";
+
+ printf("\nPASS\n");
+ return 0;
+}
+
+#else
+TEST(StressTest,
+ DISABLED_ThreadSafetyTestsAreSkippedWhenGoogleTestIsNotThreadSafe) {
+}
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif // GTEST_IS_THREADSAFE
diff --git a/Source/ThirdParty/gtest/test/gtest_test_utils.py b/Source/ThirdParty/gtest/test/gtest_test_utils.py
new file mode 100755
index 000000000..e0f5973e7
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_test_utils.py
@@ -0,0 +1,309 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test utilities for Google C++ Testing Framework."""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import atexit
+import os
+import shutil
+import sys
+import tempfile
+import unittest
+_test_module = unittest
+
+# Suppresses the 'Import not at the top of the file' lint complaint.
+# pylint: disable-msg=C6204
+try:
+ import subprocess
+ _SUBPROCESS_MODULE_AVAILABLE = True
+except:
+ import popen2
+ _SUBPROCESS_MODULE_AVAILABLE = False
+# pylint: enable-msg=C6204
+
+GTEST_OUTPUT_VAR_NAME = 'GTEST_OUTPUT'
+
+IS_WINDOWS = os.name == 'nt'
+IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0]
+
+# Here we expose a class from a particular module, depending on the
+# environment. The comment suppresses the 'Invalid variable name' lint
+# complaint.
+TestCase = _test_module.TestCase # pylint: disable-msg=C6409
+
+# Initially maps a flag to its default value. After
+# _ParseAndStripGTestFlags() is called, maps a flag to its actual value.
+_flag_map = {'gtest_source_dir': os.path.dirname(sys.argv[0]),
+ 'gtest_build_dir': os.path.dirname(sys.argv[0])}
+_gtest_flags_are_parsed = False
+
+
+def _ParseAndStripGTestFlags(argv):
+ """Parses and strips Google Test flags from argv. This is idempotent."""
+
+ # Suppresses the lint complaint about a global variable since we need it
+ # here to maintain module-wide state.
+ global _gtest_flags_are_parsed # pylint: disable-msg=W0603
+ if _gtest_flags_are_parsed:
+ return
+
+ _gtest_flags_are_parsed = True
+ for flag in _flag_map:
+ # The environment variable overrides the default value.
+ if flag.upper() in os.environ:
+ _flag_map[flag] = os.environ[flag.upper()]
+
+ # The command line flag overrides the environment variable.
+ i = 1 # Skips the program name.
+ while i < len(argv):
+ prefix = '--' + flag + '='
+ if argv[i].startswith(prefix):
+ _flag_map[flag] = argv[i][len(prefix):]
+ del argv[i]
+ break
+ else:
+ # We don't increment i in case we just found a --gtest_* flag
+ # and removed it from argv.
+ i += 1
+
+
+def GetFlag(flag):
+ """Returns the value of the given flag."""
+
+ # In case GetFlag() is called before Main(), we always call
+ # _ParseAndStripGTestFlags() here to make sure the --gtest_* flags
+ # are parsed.
+ _ParseAndStripGTestFlags(sys.argv)
+
+ return _flag_map[flag]
+
+
+def GetSourceDir():
+ """Returns the absolute path of the directory where the .py files are."""
+
+ return os.path.abspath(GetFlag('gtest_source_dir'))
+
+
+def GetBuildDir():
+ """Returns the absolute path of the directory where the test binaries are."""
+
+ return os.path.abspath(GetFlag('gtest_build_dir'))
+
+
+_temp_dir = None
+
+def _RemoveTempDir():
+ if _temp_dir:
+ shutil.rmtree(_temp_dir, ignore_errors=True)
+
+atexit.register(_RemoveTempDir)
+
+
+def GetTempDir():
+ """Returns a directory for temporary files."""
+
+ global _temp_dir
+ if not _temp_dir:
+ _temp_dir = tempfile.mkdtemp()
+ return _temp_dir
+
+
+def GetTestExecutablePath(executable_name, build_dir=None):
+ """Returns the absolute path of the test binary given its name.
+
+ The function will print a message and abort the program if the resulting file
+ doesn't exist.
+
+ Args:
+ executable_name: name of the test binary that the test script runs.
+ build_dir: directory where to look for executables, by default
+ the result of GetBuildDir().
+
+ Returns:
+ The absolute path of the test binary.
+ """
+
+ path = os.path.abspath(os.path.join(build_dir or GetBuildDir(),
+ executable_name))
+ if (IS_WINDOWS or IS_CYGWIN) and not path.endswith('.exe'):
+ path += '.exe'
+
+ if not os.path.exists(path):
+ message = (
+ 'Unable to find the test binary. Please make sure to provide path\n'
+ 'to the binary via the --gtest_build_dir flag or the GTEST_BUILD_DIR\n'
+ 'environment variable. For convenient use, invoke this script via\n'
+ 'mk_test.py.\n'
+ # TODO(vladl@google.com): change mk_test.py to test.py after renaming
+ # the file.
+ 'Please run mk_test.py -h for help.')
+ print >> sys.stderr, message
+ sys.exit(1)
+
+ return path
+
+
+def GetExitStatus(exit_code):
+ """Returns the argument to exit(), or -1 if exit() wasn't called.
+
+ Args:
+ exit_code: the result value of os.system(command).
+ """
+
+ if os.name == 'nt':
+ # On Windows, os.WEXITSTATUS() doesn't work and os.system() returns
+ # the argument to exit() directly.
+ return exit_code
+ else:
+ # On Unix, os.WEXITSTATUS() must be used to extract the exit status
+ # from the result of os.system().
+ if os.WIFEXITED(exit_code):
+ return os.WEXITSTATUS(exit_code)
+ else:
+ return -1
+
+
+class Subprocess:
+ def __init__(self, command, working_dir=None, capture_stderr=True, env=None):
+ """Changes into a specified directory, if provided, and executes a command.
+
+ Restores the old directory afterwards.
+
+ Args:
+ command: The command to run, in the form of sys.argv.
+ working_dir: The directory to change into.
+ capture_stderr: Determines whether to capture stderr in the output member
+ or to discard it.
+ env: Dictionary with environment to pass to the subprocess.
+
+ Returns:
+ An object that represents outcome of the executed process. It has the
+ following attributes:
+ terminated_by_signal True iff the child process has been terminated
+ by a signal.
+ signal Sygnal that terminated the child process.
+ exited True iff the child process exited normally.
+ exit_code The code with which the child process exited.
+ output Child process's stdout and stderr output
+ combined in a string.
+ """
+
+ # The subprocess module is the preferrable way of running programs
+ # since it is available and behaves consistently on all platforms,
+ # including Windows. But it is only available starting in python 2.4.
+ # In earlier python versions, we revert to the popen2 module, which is
+ # available in python 2.0 and later but doesn't provide required
+ # functionality (Popen4) under Windows. This allows us to support Mac
+ # OS X 10.4 Tiger, which has python 2.3 installed.
+ if _SUBPROCESS_MODULE_AVAILABLE:
+ if capture_stderr:
+ stderr = subprocess.STDOUT
+ else:
+ stderr = subprocess.PIPE
+
+ p = subprocess.Popen(command,
+ stdout=subprocess.PIPE, stderr=stderr,
+ cwd=working_dir, universal_newlines=True, env=env)
+ # communicate returns a tuple with the file obect for the child's
+ # output.
+ self.output = p.communicate()[0]
+ self._return_code = p.returncode
+ else:
+ old_dir = os.getcwd()
+
+ def _ReplaceEnvDict(dest, src):
+ # Changes made by os.environ.clear are not inheritable by child
+ # processes until Python 2.6. To produce inheritable changes we have
+ # to delete environment items with the del statement.
+ for key in dest:
+ del dest[key]
+ dest.update(src)
+
+ # When 'env' is not None, backup the environment variables and replace
+ # them with the passed 'env'. When 'env' is None, we simply use the
+ # current 'os.environ' for compatibility with the subprocess.Popen
+ # semantics used above.
+ if env is not None:
+ old_environ = os.environ.copy()
+ _ReplaceEnvDict(os.environ, env)
+
+ try:
+ if working_dir is not None:
+ os.chdir(working_dir)
+ if capture_stderr:
+ p = popen2.Popen4(command)
+ else:
+ p = popen2.Popen3(command)
+ p.tochild.close()
+ self.output = p.fromchild.read()
+ ret_code = p.wait()
+ finally:
+ os.chdir(old_dir)
+
+ # Restore the old environment variables
+ # if they were replaced.
+ if env is not None:
+ _ReplaceEnvDict(os.environ, old_environ)
+
+ # Converts ret_code to match the semantics of
+ # subprocess.Popen.returncode.
+ if os.WIFSIGNALED(ret_code):
+ self._return_code = -os.WTERMSIG(ret_code)
+ else: # os.WIFEXITED(ret_code) should return True here.
+ self._return_code = os.WEXITSTATUS(ret_code)
+
+ if self._return_code < 0:
+ self.terminated_by_signal = True
+ self.exited = False
+ self.signal = -self._return_code
+ else:
+ self.terminated_by_signal = False
+ self.exited = True
+ self.exit_code = self._return_code
+
+
+def Main():
+ """Runs the unit test."""
+
+ # We must call _ParseAndStripGTestFlags() before calling
+ # unittest.main(). Otherwise the latter will be confused by the
+ # --gtest_* flags.
+ _ParseAndStripGTestFlags(sys.argv)
+ # The tested binaries should not be writing XML output files unless the
+ # script explicitly instructs them to.
+ # TODO(vladl@google.com): Move this into Subprocess when we implement
+ # passing environment into it as a parameter.
+ if GTEST_OUTPUT_VAR_NAME in os.environ:
+ del os.environ[GTEST_OUTPUT_VAR_NAME]
+
+ _test_module.main()
diff --git a/Source/ThirdParty/gtest/test/gtest_throw_on_failure_ex_test.cc b/Source/ThirdParty/gtest/test/gtest_throw_on_failure_ex_test.cc
new file mode 100644
index 000000000..8bf9dc905
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_throw_on_failure_ex_test.cc
@@ -0,0 +1,92 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Tests Google Test's throw-on-failure mode with exceptions enabled.
+
+#include <gtest/gtest.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdexcept>
+
+// Prints the given failure message and exits the program with
+// non-zero. We use this instead of a Google Test assertion to
+// indicate a failure, as the latter is been tested and cannot be
+// relied on.
+void Fail(const char* msg) {
+ printf("FAILURE: %s\n", msg);
+ fflush(stdout);
+ exit(1);
+}
+
+// Tests that an assertion failure throws a subclass of
+// std::runtime_error.
+void TestFailureThrowsRuntimeError() {
+ testing::GTEST_FLAG(throw_on_failure) = true;
+
+ // A successful assertion shouldn't throw.
+ try {
+ EXPECT_EQ(3, 3);
+ } catch(...) {
+ Fail("A successful assertion wrongfully threw.");
+ }
+
+ // A failed assertion should throw a subclass of std::runtime_error.
+ try {
+ EXPECT_EQ(2, 3) << "Expected failure";
+ } catch(const std::runtime_error& e) {
+ if (strstr(e.what(), "Expected failure") != NULL)
+ return;
+
+ printf("%s",
+ "A failed assertion did throw an exception of the right type, "
+ "but the message is incorrect. Instead of containing \"Expected "
+ "failure\", it is:\n");
+ Fail(e.what());
+ } catch(...) {
+ Fail("A failed assertion threw the wrong type of exception.");
+ }
+ Fail("A failed assertion should've thrown but didn't.");
+}
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+
+ // We want to ensure that people can use Google Test assertions in
+ // other testing frameworks, as long as they initialize Google Test
+ // properly and set the thrown-on-failure mode. Therefore, we don't
+ // use Google Test's constructs for defining and running tests
+ // (e.g. TEST and RUN_ALL_TESTS) here.
+
+ TestFailureThrowsRuntimeError();
+ return 0;
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_throw_on_failure_test.py b/Source/ThirdParty/gtest/test/gtest_throw_on_failure_test.py
new file mode 100755
index 000000000..5678ffeaf
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_throw_on_failure_test.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+#
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests Google Test's throw-on-failure mode with exceptions disabled.
+
+This script invokes gtest_throw_on_failure_test_ (a program written with
+Google Test) with different environments and command line flags.
+"""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import os
+import gtest_test_utils
+
+
+# Constants.
+
+# The command line flag for enabling/disabling the throw-on-failure mode.
+THROW_ON_FAILURE = 'gtest_throw_on_failure'
+
+# Path to the gtest_throw_on_failure_test_ program, compiled with
+# exceptions disabled.
+EXE_PATH = gtest_test_utils.GetTestExecutablePath(
+ 'gtest_throw_on_failure_test_')
+
+
+# Utilities.
+
+
+def SetEnvVar(env_var, value):
+ """Sets an environment variable to a given value; unsets it when the
+ given value is None.
+ """
+
+ env_var = env_var.upper()
+ if value is not None:
+ os.environ[env_var] = value
+ elif env_var in os.environ:
+ del os.environ[env_var]
+
+
+def Run(command):
+ """Runs a command; returns True/False if its exit code is/isn't 0."""
+
+ print 'Running "%s". . .' % ' '.join(command)
+ p = gtest_test_utils.Subprocess(command)
+ return p.exited and p.exit_code == 0
+
+
+# The tests. TODO(wan@google.com): refactor the class to share common
+# logic with code in gtest_break_on_failure_unittest.py.
+class ThrowOnFailureTest(gtest_test_utils.TestCase):
+ """Tests the throw-on-failure mode."""
+
+ def RunAndVerify(self, env_var_value, flag_value, should_fail):
+ """Runs gtest_throw_on_failure_test_ and verifies that it does
+ (or does not) exit with a non-zero code.
+
+ Args:
+ env_var_value: value of the GTEST_BREAK_ON_FAILURE environment
+ variable; None if the variable should be unset.
+ flag_value: value of the --gtest_break_on_failure flag;
+ None if the flag should not be present.
+ should_fail: True iff the program is expected to fail.
+ """
+
+ SetEnvVar(THROW_ON_FAILURE, env_var_value)
+
+ if env_var_value is None:
+ env_var_value_msg = ' is not set'
+ else:
+ env_var_value_msg = '=' + env_var_value
+
+ if flag_value is None:
+ flag = ''
+ elif flag_value == '0':
+ flag = '--%s=0' % THROW_ON_FAILURE
+ else:
+ flag = '--%s' % THROW_ON_FAILURE
+
+ command = [EXE_PATH]
+ if flag:
+ command.append(flag)
+
+ if should_fail:
+ should_or_not = 'should'
+ else:
+ should_or_not = 'should not'
+
+ failed = not Run(command)
+
+ SetEnvVar(THROW_ON_FAILURE, None)
+
+ msg = ('when %s%s, an assertion failure in "%s" %s cause a non-zero '
+ 'exit code.' %
+ (THROW_ON_FAILURE, env_var_value_msg, ' '.join(command),
+ should_or_not))
+ self.assert_(failed == should_fail, msg)
+
+ def testDefaultBehavior(self):
+ """Tests the behavior of the default mode."""
+
+ self.RunAndVerify(env_var_value=None, flag_value=None, should_fail=False)
+
+ def testThrowOnFailureEnvVar(self):
+ """Tests using the GTEST_THROW_ON_FAILURE environment variable."""
+
+ self.RunAndVerify(env_var_value='0',
+ flag_value=None,
+ should_fail=False)
+ self.RunAndVerify(env_var_value='1',
+ flag_value=None,
+ should_fail=True)
+
+ def testThrowOnFailureFlag(self):
+ """Tests using the --gtest_throw_on_failure flag."""
+
+ self.RunAndVerify(env_var_value=None,
+ flag_value='0',
+ should_fail=False)
+ self.RunAndVerify(env_var_value=None,
+ flag_value='1',
+ should_fail=True)
+
+ def testThrowOnFailureFlagOverridesEnvVar(self):
+ """Tests that --gtest_throw_on_failure overrides GTEST_THROW_ON_FAILURE."""
+
+ self.RunAndVerify(env_var_value='0',
+ flag_value='0',
+ should_fail=False)
+ self.RunAndVerify(env_var_value='0',
+ flag_value='1',
+ should_fail=True)
+ self.RunAndVerify(env_var_value='1',
+ flag_value='0',
+ should_fail=False)
+ self.RunAndVerify(env_var_value='1',
+ flag_value='1',
+ should_fail=True)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_throw_on_failure_test_.cc b/Source/ThirdParty/gtest/test/gtest_throw_on_failure_test_.cc
new file mode 100644
index 000000000..88fbd5a76
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_throw_on_failure_test_.cc
@@ -0,0 +1,56 @@
+// Copyright 2009, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+// Tests Google Test's throw-on-failure mode with exceptions disabled.
+//
+// This program must be compiled with exceptions disabled. It will be
+// invoked by gtest_throw_on_failure_test.py, and is expected to exit
+// with non-zero in the throw-on-failure mode or 0 otherwise.
+
+#include <gtest/gtest.h>
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+
+ // We want to ensure that people can use Google Test assertions in
+ // other testing frameworks, as long as they initialize Google Test
+ // properly and set the thrown-on-failure mode. Therefore, we don't
+ // use Google Test's constructs for defining and running tests
+ // (e.g. TEST and RUN_ALL_TESTS) here.
+
+ // In the throw-on-failure mode with exceptions disabled, this
+ // assertion will cause the program to exit with a non-zero code.
+ EXPECT_EQ(2, 3);
+
+ // When not in the throw-on-failure mode, the control will reach
+ // here.
+ return 0;
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_uninitialized_test.py b/Source/ThirdParty/gtest/test/gtest_uninitialized_test.py
new file mode 100755
index 000000000..6ae57eeed
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_uninitialized_test.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Verifies that Google Test warns the user when not initialized properly."""
+
+__author__ = 'wan@google.com (Zhanyong Wan)'
+
+import gtest_test_utils
+
+
+COMMAND = gtest_test_utils.GetTestExecutablePath('gtest_uninitialized_test_')
+
+
+def Assert(condition):
+ if not condition:
+ raise AssertionError
+
+
+def AssertEq(expected, actual):
+ if expected != actual:
+ print 'Expected: %s' % (expected,)
+ print ' Actual: %s' % (actual,)
+ raise AssertionError
+
+
+def TestExitCodeAndOutput(command):
+ """Runs the given command and verifies its exit code and output."""
+
+ # Verifies that 'command' exits with code 1.
+ p = gtest_test_utils.Subprocess(command)
+ Assert(p.exited)
+ AssertEq(1, p.exit_code)
+ Assert('InitGoogleTest' in p.output)
+
+
+class GTestUninitializedTest(gtest_test_utils.TestCase):
+ def testExitCodeAndOutput(self):
+ TestExitCodeAndOutput(COMMAND)
+
+
+if __name__ == '__main__':
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_uninitialized_test_.cc b/Source/ThirdParty/gtest/test/gtest_uninitialized_test_.cc
new file mode 100644
index 000000000..e8b2aa81d
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_uninitialized_test_.cc
@@ -0,0 +1,43 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+
+#include <gtest/gtest.h>
+
+TEST(DummyTest, Dummy) {
+ // This test doesn't verify anything. We just need it to create a
+ // realistic stage for testing the behavior of Google Test when
+ // RUN_ALL_TESTS() is called without testing::InitGoogleTest() being
+ // called first.
+}
+
+int main() {
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_unittest.cc b/Source/ThirdParty/gtest/test/gtest_unittest.cc
new file mode 100644
index 000000000..a14f065a2
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_unittest.cc
@@ -0,0 +1,6718 @@
+// Copyright 2005, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// Tests for Google Test itself. This verifies that the basic constructs of
+// Google Test work.
+
+#include <gtest/gtest.h>
+#include <vector>
+
+// Verifies that the command line flag variables can be accessed
+// in code once <gtest/gtest.h> has been #included.
+// Do not move it after other #includes.
+TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) {
+ bool dummy = testing::GTEST_FLAG(also_run_disabled_tests)
+ || testing::GTEST_FLAG(break_on_failure)
+ || testing::GTEST_FLAG(catch_exceptions)
+ || testing::GTEST_FLAG(color) != "unknown"
+ || testing::GTEST_FLAG(filter) != "unknown"
+ || testing::GTEST_FLAG(list_tests)
+ || testing::GTEST_FLAG(output) != "unknown"
+ || testing::GTEST_FLAG(print_time)
+ || testing::GTEST_FLAG(random_seed)
+ || testing::GTEST_FLAG(repeat) > 0
+ || testing::GTEST_FLAG(show_internal_stack_frames)
+ || testing::GTEST_FLAG(shuffle)
+ || testing::GTEST_FLAG(stack_trace_depth) > 0
+ || testing::GTEST_FLAG(throw_on_failure);
+ EXPECT_TRUE(dummy || !dummy); // Suppresses warning that dummy is unused.
+}
+
+#include <gtest/gtest-spi.h>
+
+// Indicates that this translation unit is part of Google Test's
+// implementation. It must come before gtest-internal-inl.h is
+// included, or there will be a compiler error. This trick is to
+// prevent a user from accidentally including gtest-internal-inl.h in
+// his code.
+#define GTEST_IMPLEMENTATION_ 1
+#include "src/gtest-internal-inl.h"
+#undef GTEST_IMPLEMENTATION_
+
+#include <limits.h> // For INT_MAX.
+#include <stdlib.h>
+#include <time.h>
+
+#include <map>
+
+namespace testing {
+namespace internal {
+
+// Provides access to otherwise private parts of the TestEventListeners class
+// that are needed to test it.
+class TestEventListenersAccessor {
+ public:
+ static TestEventListener* GetRepeater(TestEventListeners* listeners) {
+ return listeners->repeater();
+ }
+
+ static void SetDefaultResultPrinter(TestEventListeners* listeners,
+ TestEventListener* listener) {
+ listeners->SetDefaultResultPrinter(listener);
+ }
+ static void SetDefaultXmlGenerator(TestEventListeners* listeners,
+ TestEventListener* listener) {
+ listeners->SetDefaultXmlGenerator(listener);
+ }
+
+ static bool EventForwardingEnabled(const TestEventListeners& listeners) {
+ return listeners.EventForwardingEnabled();
+ }
+
+ static void SuppressEventForwarding(TestEventListeners* listeners) {
+ listeners->SuppressEventForwarding();
+ }
+};
+
+} // namespace internal
+} // namespace testing
+
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
+using testing::DoubleLE;
+using testing::EmptyTestEventListener;
+using testing::FloatLE;
+using testing::GTEST_FLAG(also_run_disabled_tests);
+using testing::GTEST_FLAG(break_on_failure);
+using testing::GTEST_FLAG(catch_exceptions);
+using testing::GTEST_FLAG(color);
+using testing::GTEST_FLAG(death_test_use_fork);
+using testing::GTEST_FLAG(filter);
+using testing::GTEST_FLAG(list_tests);
+using testing::GTEST_FLAG(output);
+using testing::GTEST_FLAG(print_time);
+using testing::GTEST_FLAG(random_seed);
+using testing::GTEST_FLAG(repeat);
+using testing::GTEST_FLAG(show_internal_stack_frames);
+using testing::GTEST_FLAG(shuffle);
+using testing::GTEST_FLAG(stack_trace_depth);
+using testing::GTEST_FLAG(throw_on_failure);
+using testing::IsNotSubstring;
+using testing::IsSubstring;
+using testing::Message;
+using testing::ScopedFakeTestPartResultReporter;
+using testing::StaticAssertTypeEq;
+using testing::Test;
+using testing::TestEventListeners;
+using testing::TestCase;
+using testing::TestPartResult;
+using testing::TestPartResultArray;
+using testing::TestProperty;
+using testing::TestResult;
+using testing::UnitTest;
+using testing::kMaxStackTraceDepth;
+using testing::internal::AlwaysFalse;
+using testing::internal::AlwaysTrue;
+using testing::internal::AppendUserMessage;
+using testing::internal::CodePointToUtf8;
+using testing::internal::CountIf;
+using testing::internal::EqFailure;
+using testing::internal::FloatingPoint;
+using testing::internal::FormatTimeInMillisAsSeconds;
+using testing::internal::ForEach;
+using testing::internal::GTestFlagSaver;
+using testing::internal::GetCurrentOsStackTraceExceptTop;
+using testing::internal::GetElementOr;
+using testing::internal::GetNextRandomSeed;
+using testing::internal::GetRandomSeedFromFlag;
+using testing::internal::GetTestTypeId;
+using testing::internal::GetTypeId;
+using testing::internal::GetUnitTestImpl;
+using testing::internal::Int32;
+using testing::internal::Int32FromEnvOrDie;
+using testing::internal::ParseInt32Flag;
+using testing::internal::ShouldRunTestOnShard;
+using testing::internal::ShouldShard;
+using testing::internal::ShouldUseColor;
+using testing::internal::Shuffle;
+using testing::internal::ShuffleRange;
+using testing::internal::StreamableToString;
+using testing::internal::String;
+using testing::internal::TestEventListenersAccessor;
+using testing::internal::TestResultAccessor;
+using testing::internal::UInt32;
+using testing::internal::WideStringToUtf8;
+using testing::internal::kMaxRandomSeed;
+using testing::internal::kTestTypeIdInGoogleTest;
+using testing::internal::scoped_ptr;
+
+#if GTEST_HAS_STREAM_REDIRECTION_
+using testing::internal::CaptureStdout;
+using testing::internal::GetCapturedStdout;
+#endif // GTEST_HAS_STREAM_REDIRECTION_
+
+#if GTEST_IS_THREADSAFE
+using testing::internal::ThreadWithParam;
+#endif
+
+class TestingVector : public std::vector<int> {
+};
+
+::std::ostream& operator<<(::std::ostream& os,
+ const TestingVector& vector) {
+ os << "{ ";
+ for (size_t i = 0; i < vector.size(); i++) {
+ os << vector[i] << " ";
+ }
+ os << "}";
+ return os;
+}
+
+// This line tests that we can define tests in an unnamed namespace.
+namespace {
+
+TEST(GetRandomSeedFromFlagTest, HandlesZero) {
+ const int seed = GetRandomSeedFromFlag(0);
+ EXPECT_LE(1, seed);
+ EXPECT_LE(seed, static_cast<int>(kMaxRandomSeed));
+}
+
+TEST(GetRandomSeedFromFlagTest, PreservesValidSeed) {
+ EXPECT_EQ(1, GetRandomSeedFromFlag(1));
+ EXPECT_EQ(2, GetRandomSeedFromFlag(2));
+ EXPECT_EQ(kMaxRandomSeed - 1, GetRandomSeedFromFlag(kMaxRandomSeed - 1));
+ EXPECT_EQ(static_cast<int>(kMaxRandomSeed),
+ GetRandomSeedFromFlag(kMaxRandomSeed));
+}
+
+TEST(GetRandomSeedFromFlagTest, NormalizesInvalidSeed) {
+ const int seed1 = GetRandomSeedFromFlag(-1);
+ EXPECT_LE(1, seed1);
+ EXPECT_LE(seed1, static_cast<int>(kMaxRandomSeed));
+
+ const int seed2 = GetRandomSeedFromFlag(kMaxRandomSeed + 1);
+ EXPECT_LE(1, seed2);
+ EXPECT_LE(seed2, static_cast<int>(kMaxRandomSeed));
+}
+
+TEST(GetNextRandomSeedTest, WorksForValidInput) {
+ EXPECT_EQ(2, GetNextRandomSeed(1));
+ EXPECT_EQ(3, GetNextRandomSeed(2));
+ EXPECT_EQ(static_cast<int>(kMaxRandomSeed),
+ GetNextRandomSeed(kMaxRandomSeed - 1));
+ EXPECT_EQ(1, GetNextRandomSeed(kMaxRandomSeed));
+
+ // We deliberately don't test GetNextRandomSeed() with invalid
+ // inputs, as that requires death tests, which are expensive. This
+ // is fine as GetNextRandomSeed() is internal and has a
+ // straightforward definition.
+}
+
+static void ClearCurrentTestPartResults() {
+ TestResultAccessor::ClearTestPartResults(
+ GetUnitTestImpl()->current_test_result());
+}
+
+// Tests GetTypeId.
+
+TEST(GetTypeIdTest, ReturnsSameValueForSameType) {
+ EXPECT_EQ(GetTypeId<int>(), GetTypeId<int>());
+ EXPECT_EQ(GetTypeId<Test>(), GetTypeId<Test>());
+}
+
+class SubClassOfTest : public Test {};
+class AnotherSubClassOfTest : public Test {};
+
+TEST(GetTypeIdTest, ReturnsDifferentValuesForDifferentTypes) {
+ EXPECT_NE(GetTypeId<int>(), GetTypeId<const int>());
+ EXPECT_NE(GetTypeId<int>(), GetTypeId<char>());
+ EXPECT_NE(GetTypeId<int>(), GetTestTypeId());
+ EXPECT_NE(GetTypeId<SubClassOfTest>(), GetTestTypeId());
+ EXPECT_NE(GetTypeId<AnotherSubClassOfTest>(), GetTestTypeId());
+ EXPECT_NE(GetTypeId<AnotherSubClassOfTest>(), GetTypeId<SubClassOfTest>());
+}
+
+// Verifies that GetTestTypeId() returns the same value, no matter it
+// is called from inside Google Test or outside of it.
+TEST(GetTestTypeIdTest, ReturnsTheSameValueInsideOrOutsideOfGoogleTest) {
+ EXPECT_EQ(kTestTypeIdInGoogleTest, GetTestTypeId());
+}
+
+// Tests FormatTimeInMillisAsSeconds().
+
+TEST(FormatTimeInMillisAsSecondsTest, FormatsZero) {
+ EXPECT_EQ("0", FormatTimeInMillisAsSeconds(0));
+}
+
+TEST(FormatTimeInMillisAsSecondsTest, FormatsPositiveNumber) {
+ EXPECT_EQ("0.003", FormatTimeInMillisAsSeconds(3));
+ EXPECT_EQ("0.01", FormatTimeInMillisAsSeconds(10));
+ EXPECT_EQ("0.2", FormatTimeInMillisAsSeconds(200));
+ EXPECT_EQ("1.2", FormatTimeInMillisAsSeconds(1200));
+ EXPECT_EQ("3", FormatTimeInMillisAsSeconds(3000));
+}
+
+TEST(FormatTimeInMillisAsSecondsTest, FormatsNegativeNumber) {
+ EXPECT_EQ("-0.003", FormatTimeInMillisAsSeconds(-3));
+ EXPECT_EQ("-0.01", FormatTimeInMillisAsSeconds(-10));
+ EXPECT_EQ("-0.2", FormatTimeInMillisAsSeconds(-200));
+ EXPECT_EQ("-1.2", FormatTimeInMillisAsSeconds(-1200));
+ EXPECT_EQ("-3", FormatTimeInMillisAsSeconds(-3000));
+}
+
+#if GTEST_CAN_COMPARE_NULL
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true", "Unreachable code"
+#pragma option push -w-ccc -w-rch
+#endif
+
+// Tests that GTEST_IS_NULL_LITERAL_(x) is true when x is a null
+// pointer literal.
+TEST(NullLiteralTest, IsTrueForNullLiterals) {
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(NULL));
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0));
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0U));
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(0L));
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(false));
+#ifndef __BORLANDC__
+ // Some compilers may fail to detect some null pointer literals;
+ // as long as users of the framework don't use such literals, this
+ // is harmless.
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(1 - 1));
+ EXPECT_TRUE(GTEST_IS_NULL_LITERAL_(true && false));
+#endif
+}
+
+// Tests that GTEST_IS_NULL_LITERAL_(x) is false when x is not a null
+// pointer literal.
+TEST(NullLiteralTest, IsFalseForNonNullLiterals) {
+ EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(1));
+ EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(0.0));
+ EXPECT_FALSE(GTEST_IS_NULL_LITERAL_('a'));
+ EXPECT_FALSE(GTEST_IS_NULL_LITERAL_(static_cast<void*>(NULL)));
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" suppressed them.
+#pragma option pop
+#endif
+
+#endif // GTEST_CAN_COMPARE_NULL
+//
+// Tests CodePointToUtf8().
+
+// Tests that the NUL character L'\0' is encoded correctly.
+TEST(CodePointToUtf8Test, CanEncodeNul) {
+ char buffer[32];
+ EXPECT_STREQ("", CodePointToUtf8(L'\0', buffer));
+}
+
+// Tests that ASCII characters are encoded correctly.
+TEST(CodePointToUtf8Test, CanEncodeAscii) {
+ char buffer[32];
+ EXPECT_STREQ("a", CodePointToUtf8(L'a', buffer));
+ EXPECT_STREQ("Z", CodePointToUtf8(L'Z', buffer));
+ EXPECT_STREQ("&", CodePointToUtf8(L'&', buffer));
+ EXPECT_STREQ("\x7F", CodePointToUtf8(L'\x7F', buffer));
+}
+
+// Tests that Unicode code-points that have 8 to 11 bits are encoded
+// as 110xxxxx 10xxxxxx.
+TEST(CodePointToUtf8Test, CanEncode8To11Bits) {
+ char buffer[32];
+ // 000 1101 0011 => 110-00011 10-010011
+ EXPECT_STREQ("\xC3\x93", CodePointToUtf8(L'\xD3', buffer));
+
+ // 101 0111 0110 => 110-10101 10-110110
+ EXPECT_STREQ("\xD5\xB6", CodePointToUtf8(L'\x576', buffer));
+}
+
+// Tests that Unicode code-points that have 12 to 16 bits are encoded
+// as 1110xxxx 10xxxxxx 10xxxxxx.
+TEST(CodePointToUtf8Test, CanEncode12To16Bits) {
+ char buffer[32];
+ // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011
+ EXPECT_STREQ("\xE0\xA3\x93", CodePointToUtf8(L'\x8D3', buffer));
+
+ // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101
+ EXPECT_STREQ("\xEC\x9D\x8D", CodePointToUtf8(L'\xC74D', buffer));
+}
+
+#if !GTEST_WIDE_STRING_USES_UTF16_
+// Tests in this group require a wchar_t to hold > 16 bits, and thus
+// are skipped on Windows, Cygwin, and Symbian, where a wchar_t is
+// 16-bit wide. This code may not compile on those systems.
+
+// Tests that Unicode code-points that have 17 to 21 bits are encoded
+// as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx.
+TEST(CodePointToUtf8Test, CanEncode17To21Bits) {
+ char buffer[32];
+ // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011
+ EXPECT_STREQ("\xF0\x90\xA3\x93", CodePointToUtf8(L'\x108D3', buffer));
+
+ // 0 0001 0000 0100 0000 0000 => 11110-000 10-010000 10-010000 10-000000
+ EXPECT_STREQ("\xF0\x90\x90\x80", CodePointToUtf8(L'\x10400', buffer));
+
+ // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100
+ EXPECT_STREQ("\xF4\x88\x98\xB4", CodePointToUtf8(L'\x108634', buffer));
+}
+
+// Tests that encoding an invalid code-point generates the expected result.
+TEST(CodePointToUtf8Test, CanEncodeInvalidCodePoint) {
+ char buffer[32];
+ EXPECT_STREQ("(Invalid Unicode 0x1234ABCD)",
+ CodePointToUtf8(L'\x1234ABCD', buffer));
+}
+
+#endif // !GTEST_WIDE_STRING_USES_UTF16_
+
+// Tests WideStringToUtf8().
+
+// Tests that the NUL character L'\0' is encoded correctly.
+TEST(WideStringToUtf8Test, CanEncodeNul) {
+ EXPECT_STREQ("", WideStringToUtf8(L"", 0).c_str());
+ EXPECT_STREQ("", WideStringToUtf8(L"", -1).c_str());
+}
+
+// Tests that ASCII strings are encoded correctly.
+TEST(WideStringToUtf8Test, CanEncodeAscii) {
+ EXPECT_STREQ("a", WideStringToUtf8(L"a", 1).c_str());
+ EXPECT_STREQ("ab", WideStringToUtf8(L"ab", 2).c_str());
+ EXPECT_STREQ("a", WideStringToUtf8(L"a", -1).c_str());
+ EXPECT_STREQ("ab", WideStringToUtf8(L"ab", -1).c_str());
+}
+
+// Tests that Unicode code-points that have 8 to 11 bits are encoded
+// as 110xxxxx 10xxxxxx.
+TEST(WideStringToUtf8Test, CanEncode8To11Bits) {
+ // 000 1101 0011 => 110-00011 10-010011
+ EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", 1).c_str());
+ EXPECT_STREQ("\xC3\x93", WideStringToUtf8(L"\xD3", -1).c_str());
+
+ // 101 0111 0110 => 110-10101 10-110110
+ EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(L"\x576", 1).c_str());
+ EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(L"\x576", -1).c_str());
+}
+
+// Tests that Unicode code-points that have 12 to 16 bits are encoded
+// as 1110xxxx 10xxxxxx 10xxxxxx.
+TEST(WideStringToUtf8Test, CanEncode12To16Bits) {
+ // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011
+ EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(L"\x8D3", 1).c_str());
+ EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(L"\x8D3", -1).c_str());
+
+ // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101
+ EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(L"\xC74D", 1).c_str());
+ EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(L"\xC74D", -1).c_str());
+}
+
+// Tests that the conversion stops when the function encounters \0 character.
+TEST(WideStringToUtf8Test, StopsOnNulCharacter) {
+ EXPECT_STREQ("ABC", WideStringToUtf8(L"ABC\0XYZ", 100).c_str());
+}
+
+// Tests that the conversion stops when the function reaches the limit
+// specified by the 'length' parameter.
+TEST(WideStringToUtf8Test, StopsWhenLengthLimitReached) {
+ EXPECT_STREQ("ABC", WideStringToUtf8(L"ABCDEF", 3).c_str());
+}
+
+
+#if !GTEST_WIDE_STRING_USES_UTF16_
+// Tests that Unicode code-points that have 17 to 21 bits are encoded
+// as 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx. This code may not compile
+// on the systems using UTF-16 encoding.
+TEST(WideStringToUtf8Test, CanEncode17To21Bits) {
+ // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011
+ EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", 1).c_str());
+ EXPECT_STREQ("\xF0\x90\xA3\x93", WideStringToUtf8(L"\x108D3", -1).c_str());
+
+ // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100
+ EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", 1).c_str());
+ EXPECT_STREQ("\xF4\x88\x98\xB4", WideStringToUtf8(L"\x108634", -1).c_str());
+}
+
+// Tests that encoding an invalid code-point generates the expected result.
+TEST(WideStringToUtf8Test, CanEncodeInvalidCodePoint) {
+ EXPECT_STREQ("(Invalid Unicode 0xABCDFF)",
+ WideStringToUtf8(L"\xABCDFF", -1).c_str());
+}
+#else // !GTEST_WIDE_STRING_USES_UTF16_
+// Tests that surrogate pairs are encoded correctly on the systems using
+// UTF-16 encoding in the wide strings.
+TEST(WideStringToUtf8Test, CanEncodeValidUtf16SUrrogatePairs) {
+ EXPECT_STREQ("\xF0\x90\x90\x80",
+ WideStringToUtf8(L"\xD801\xDC00", -1).c_str());
+}
+
+// Tests that encoding an invalid UTF-16 surrogate pair
+// generates the expected result.
+TEST(WideStringToUtf8Test, CanEncodeInvalidUtf16SurrogatePair) {
+ // Leading surrogate is at the end of the string.
+ EXPECT_STREQ("\xED\xA0\x80", WideStringToUtf8(L"\xD800", -1).c_str());
+ // Leading surrogate is not followed by the trailing surrogate.
+ EXPECT_STREQ("\xED\xA0\x80$", WideStringToUtf8(L"\xD800$", -1).c_str());
+ // Trailing surrogate appearas without a leading surrogate.
+ EXPECT_STREQ("\xED\xB0\x80PQR", WideStringToUtf8(L"\xDC00PQR", -1).c_str());
+}
+#endif // !GTEST_WIDE_STRING_USES_UTF16_
+
+// Tests that codepoint concatenation works correctly.
+#if !GTEST_WIDE_STRING_USES_UTF16_
+TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) {
+ EXPECT_STREQ(
+ "\xF4\x88\x98\xB4"
+ "\xEC\x9D\x8D"
+ "\n"
+ "\xD5\xB6"
+ "\xE0\xA3\x93"
+ "\xF4\x88\x98\xB4",
+ WideStringToUtf8(L"\x108634\xC74D\n\x576\x8D3\x108634", -1).c_str());
+}
+#else
+TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) {
+ EXPECT_STREQ(
+ "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93",
+ WideStringToUtf8(L"\xC74D\n\x576\x8D3", -1).c_str());
+}
+#endif // !GTEST_WIDE_STRING_USES_UTF16_
+
+// Tests the Random class.
+
+TEST(RandomDeathTest, GeneratesCrashesOnInvalidRange) {
+ testing::internal::Random random(42);
+ EXPECT_DEATH_IF_SUPPORTED(
+ random.Generate(0),
+ "Cannot generate a number in the range \\[0, 0\\)");
+ EXPECT_DEATH_IF_SUPPORTED(
+ random.Generate(testing::internal::Random::kMaxRange + 1),
+ "Generation of a number in \\[0, 2147483649\\) was requested, "
+ "but this can only generate numbers in \\[0, 2147483648\\)");
+}
+
+TEST(RandomTest, GeneratesNumbersWithinRange) {
+ const UInt32 kRange = 10000;
+ testing::internal::Random random(12345);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_LT(random.Generate(kRange), kRange) << " for iteration " << i;
+ }
+
+ testing::internal::Random random2(testing::internal::Random::kMaxRange);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_LT(random2.Generate(kRange), kRange) << " for iteration " << i;
+ }
+}
+
+TEST(RandomTest, RepeatsWhenReseeded) {
+ const int kSeed = 123;
+ const int kArraySize = 10;
+ const UInt32 kRange = 10000;
+ UInt32 values[kArraySize];
+
+ testing::internal::Random random(kSeed);
+ for (int i = 0; i < kArraySize; i++) {
+ values[i] = random.Generate(kRange);
+ }
+
+ random.Reseed(kSeed);
+ for (int i = 0; i < kArraySize; i++) {
+ EXPECT_EQ(values[i], random.Generate(kRange)) << " for iteration " << i;
+ }
+}
+
+// Tests STL container utilities.
+
+// Tests CountIf().
+
+static bool IsPositive(int n) { return n > 0; }
+
+TEST(ContainerUtilityTest, CountIf) {
+ std::vector<int> v;
+ EXPECT_EQ(0, CountIf(v, IsPositive)); // Works for an empty container.
+
+ v.push_back(-1);
+ v.push_back(0);
+ EXPECT_EQ(0, CountIf(v, IsPositive)); // Works when no value satisfies.
+
+ v.push_back(2);
+ v.push_back(-10);
+ v.push_back(10);
+ EXPECT_EQ(2, CountIf(v, IsPositive));
+}
+
+// Tests ForEach().
+
+static int g_sum = 0;
+static void Accumulate(int n) { g_sum += n; }
+
+TEST(ContainerUtilityTest, ForEach) {
+ std::vector<int> v;
+ g_sum = 0;
+ ForEach(v, Accumulate);
+ EXPECT_EQ(0, g_sum); // Works for an empty container;
+
+ g_sum = 0;
+ v.push_back(1);
+ ForEach(v, Accumulate);
+ EXPECT_EQ(1, g_sum); // Works for a container with one element.
+
+ g_sum = 0;
+ v.push_back(20);
+ v.push_back(300);
+ ForEach(v, Accumulate);
+ EXPECT_EQ(321, g_sum);
+}
+
+// Tests GetElementOr().
+TEST(ContainerUtilityTest, GetElementOr) {
+ std::vector<char> a;
+ EXPECT_EQ('x', GetElementOr(a, 0, 'x'));
+
+ a.push_back('a');
+ a.push_back('b');
+ EXPECT_EQ('a', GetElementOr(a, 0, 'x'));
+ EXPECT_EQ('b', GetElementOr(a, 1, 'x'));
+ EXPECT_EQ('x', GetElementOr(a, -2, 'x'));
+ EXPECT_EQ('x', GetElementOr(a, 2, 'x'));
+}
+
+TEST(ContainerUtilityDeathTest, ShuffleRange) {
+ std::vector<int> a;
+ a.push_back(0);
+ a.push_back(1);
+ a.push_back(2);
+ testing::internal::Random random(1);
+
+ EXPECT_DEATH_IF_SUPPORTED(
+ ShuffleRange(&random, -1, 1, &a),
+ "Invalid shuffle range start -1: must be in range \\[0, 3\\]");
+ EXPECT_DEATH_IF_SUPPORTED(
+ ShuffleRange(&random, 4, 4, &a),
+ "Invalid shuffle range start 4: must be in range \\[0, 3\\]");
+ EXPECT_DEATH_IF_SUPPORTED(
+ ShuffleRange(&random, 3, 2, &a),
+ "Invalid shuffle range finish 2: must be in range \\[3, 3\\]");
+ EXPECT_DEATH_IF_SUPPORTED(
+ ShuffleRange(&random, 3, 4, &a),
+ "Invalid shuffle range finish 4: must be in range \\[3, 3\\]");
+}
+
+class VectorShuffleTest : public Test {
+ protected:
+ static const int kVectorSize = 20;
+
+ VectorShuffleTest() : random_(1) {
+ for (int i = 0; i < kVectorSize; i++) {
+ vector_.push_back(i);
+ }
+ }
+
+ static bool VectorIsCorrupt(const TestingVector& vector) {
+ if (kVectorSize != static_cast<int>(vector.size())) {
+ return true;
+ }
+
+ bool found_in_vector[kVectorSize] = { false };
+ for (size_t i = 0; i < vector.size(); i++) {
+ const int e = vector[i];
+ if (e < 0 || e >= kVectorSize || found_in_vector[e]) {
+ return true;
+ }
+ found_in_vector[e] = true;
+ }
+
+ // Vector size is correct, elements' range is correct, no
+ // duplicate elements. Therefore no corruption has occurred.
+ return false;
+ }
+
+ static bool VectorIsNotCorrupt(const TestingVector& vector) {
+ return !VectorIsCorrupt(vector);
+ }
+
+ static bool RangeIsShuffled(const TestingVector& vector, int begin, int end) {
+ for (int i = begin; i < end; i++) {
+ if (i != vector[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static bool RangeIsUnshuffled(
+ const TestingVector& vector, int begin, int end) {
+ return !RangeIsShuffled(vector, begin, end);
+ }
+
+ static bool VectorIsShuffled(const TestingVector& vector) {
+ return RangeIsShuffled(vector, 0, static_cast<int>(vector.size()));
+ }
+
+ static bool VectorIsUnshuffled(const TestingVector& vector) {
+ return !VectorIsShuffled(vector);
+ }
+
+ testing::internal::Random random_;
+ TestingVector vector_;
+}; // class VectorShuffleTest
+
+const int VectorShuffleTest::kVectorSize;
+
+TEST_F(VectorShuffleTest, HandlesEmptyRange) {
+ // Tests an empty range at the beginning...
+ ShuffleRange(&random_, 0, 0, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...in the middle...
+ ShuffleRange(&random_, kVectorSize/2, kVectorSize/2, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...at the end...
+ ShuffleRange(&random_, kVectorSize - 1, kVectorSize - 1, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...and past the end.
+ ShuffleRange(&random_, kVectorSize, kVectorSize, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+}
+
+TEST_F(VectorShuffleTest, HandlesRangeOfSizeOne) {
+ // Tests a size one range at the beginning...
+ ShuffleRange(&random_, 0, 1, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...in the middle...
+ ShuffleRange(&random_, kVectorSize/2, kVectorSize/2 + 1, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+
+ // ...and at the end.
+ ShuffleRange(&random_, kVectorSize - 1, kVectorSize, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsUnshuffled, vector_);
+}
+
+// Because we use our own random number generator and a fixed seed,
+// we can guarantee that the following "random" tests will succeed.
+
+TEST_F(VectorShuffleTest, ShufflesEntireVector) {
+ Shuffle(&random_, &vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ EXPECT_FALSE(VectorIsUnshuffled(vector_)) << vector_;
+
+ // Tests the first and last elements in particular to ensure that
+ // there are no off-by-one problems in our shuffle algorithm.
+ EXPECT_NE(0, vector_[0]);
+ EXPECT_NE(kVectorSize - 1, vector_[kVectorSize - 1]);
+}
+
+TEST_F(VectorShuffleTest, ShufflesStartOfVector) {
+ const int kRangeSize = kVectorSize/2;
+
+ ShuffleRange(&random_, 0, kRangeSize, &vector_);
+
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ EXPECT_PRED3(RangeIsShuffled, vector_, 0, kRangeSize);
+ EXPECT_PRED3(RangeIsUnshuffled, vector_, kRangeSize, kVectorSize);
+}
+
+TEST_F(VectorShuffleTest, ShufflesEndOfVector) {
+ const int kRangeSize = kVectorSize / 2;
+ ShuffleRange(&random_, kRangeSize, kVectorSize, &vector_);
+
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize);
+ EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, kVectorSize);
+}
+
+TEST_F(VectorShuffleTest, ShufflesMiddleOfVector) {
+ int kRangeSize = kVectorSize/3;
+ ShuffleRange(&random_, kRangeSize, 2*kRangeSize, &vector_);
+
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ EXPECT_PRED3(RangeIsUnshuffled, vector_, 0, kRangeSize);
+ EXPECT_PRED3(RangeIsShuffled, vector_, kRangeSize, 2*kRangeSize);
+ EXPECT_PRED3(RangeIsUnshuffled, vector_, 2*kRangeSize, kVectorSize);
+}
+
+TEST_F(VectorShuffleTest, ShufflesRepeatably) {
+ TestingVector vector2;
+ for (int i = 0; i < kVectorSize; i++) {
+ vector2.push_back(i);
+ }
+
+ random_.Reseed(1234);
+ Shuffle(&random_, &vector_);
+ random_.Reseed(1234);
+ Shuffle(&random_, &vector2);
+
+ ASSERT_PRED1(VectorIsNotCorrupt, vector_);
+ ASSERT_PRED1(VectorIsNotCorrupt, vector2);
+
+ for (int i = 0; i < kVectorSize; i++) {
+ EXPECT_EQ(vector_[i], vector2[i]) << " where i is " << i;
+ }
+}
+
+// Tests the size of the AssertHelper class.
+
+TEST(AssertHelperTest, AssertHelperIsSmall) {
+ // To avoid breaking clients that use lots of assertions in one
+ // function, we cannot grow the size of AssertHelper.
+ EXPECT_LE(sizeof(testing::internal::AssertHelper), sizeof(void*));
+}
+
+// Tests the String class.
+
+// Tests String's constructors.
+TEST(StringTest, Constructors) {
+ // Default ctor.
+ String s1;
+ // We aren't using EXPECT_EQ(NULL, s1.c_str()) because comparing
+ // pointers with NULL isn't supported on all platforms.
+ EXPECT_EQ(0U, s1.length());
+ EXPECT_TRUE(NULL == s1.c_str());
+
+ // Implicitly constructs from a C-string.
+ String s2 = "Hi";
+ EXPECT_EQ(2U, s2.length());
+ EXPECT_STREQ("Hi", s2.c_str());
+
+ // Constructs from a C-string and a length.
+ String s3("hello", 3);
+ EXPECT_EQ(3U, s3.length());
+ EXPECT_STREQ("hel", s3.c_str());
+
+ // The empty String should be created when String is constructed with
+ // a NULL pointer and length 0.
+ EXPECT_EQ(0U, String(NULL, 0).length());
+ EXPECT_FALSE(String(NULL, 0).c_str() == NULL);
+
+ // Constructs a String that contains '\0'.
+ String s4("a\0bcd", 4);
+ EXPECT_EQ(4U, s4.length());
+ EXPECT_EQ('a', s4.c_str()[0]);
+ EXPECT_EQ('\0', s4.c_str()[1]);
+ EXPECT_EQ('b', s4.c_str()[2]);
+ EXPECT_EQ('c', s4.c_str()[3]);
+
+ // Copy ctor where the source is NULL.
+ const String null_str;
+ String s5 = null_str;
+ EXPECT_TRUE(s5.c_str() == NULL);
+
+ // Copy ctor where the source isn't NULL.
+ String s6 = s3;
+ EXPECT_EQ(3U, s6.length());
+ EXPECT_STREQ("hel", s6.c_str());
+
+ // Copy ctor where the source contains '\0'.
+ String s7 = s4;
+ EXPECT_EQ(4U, s7.length());
+ EXPECT_EQ('a', s7.c_str()[0]);
+ EXPECT_EQ('\0', s7.c_str()[1]);
+ EXPECT_EQ('b', s7.c_str()[2]);
+ EXPECT_EQ('c', s7.c_str()[3]);
+}
+
+TEST(StringTest, ConvertsFromStdString) {
+ // An empty std::string.
+ const std::string src1("");
+ const String dest1 = src1;
+ EXPECT_EQ(0U, dest1.length());
+ EXPECT_STREQ("", dest1.c_str());
+
+ // A normal std::string.
+ const std::string src2("Hi");
+ const String dest2 = src2;
+ EXPECT_EQ(2U, dest2.length());
+ EXPECT_STREQ("Hi", dest2.c_str());
+
+ // An std::string with an embedded NUL character.
+ const char src3[] = "a\0b";
+ const String dest3 = std::string(src3, sizeof(src3));
+ EXPECT_EQ(sizeof(src3), dest3.length());
+ EXPECT_EQ('a', dest3.c_str()[0]);
+ EXPECT_EQ('\0', dest3.c_str()[1]);
+ EXPECT_EQ('b', dest3.c_str()[2]);
+}
+
+TEST(StringTest, ConvertsToStdString) {
+ // An empty String.
+ const String src1("");
+ const std::string dest1 = src1;
+ EXPECT_EQ("", dest1);
+
+ // A normal String.
+ const String src2("Hi");
+ const std::string dest2 = src2;
+ EXPECT_EQ("Hi", dest2);
+
+ // A String containing a '\0'.
+ const String src3("x\0y", 3);
+ const std::string dest3 = src3;
+ EXPECT_EQ(std::string("x\0y", 3), dest3);
+}
+
+#if GTEST_HAS_GLOBAL_STRING
+
+TEST(StringTest, ConvertsFromGlobalString) {
+ // An empty ::string.
+ const ::string src1("");
+ const String dest1 = src1;
+ EXPECT_EQ(0U, dest1.length());
+ EXPECT_STREQ("", dest1.c_str());
+
+ // A normal ::string.
+ const ::string src2("Hi");
+ const String dest2 = src2;
+ EXPECT_EQ(2U, dest2.length());
+ EXPECT_STREQ("Hi", dest2.c_str());
+
+ // An ::string with an embedded NUL character.
+ const char src3[] = "x\0y";
+ const String dest3 = ::string(src3, sizeof(src3));
+ EXPECT_EQ(sizeof(src3), dest3.length());
+ EXPECT_EQ('x', dest3.c_str()[0]);
+ EXPECT_EQ('\0', dest3.c_str()[1]);
+ EXPECT_EQ('y', dest3.c_str()[2]);
+}
+
+TEST(StringTest, ConvertsToGlobalString) {
+ // An empty String.
+ const String src1("");
+ const ::string dest1 = src1;
+ EXPECT_EQ("", dest1);
+
+ // A normal String.
+ const String src2("Hi");
+ const ::string dest2 = src2;
+ EXPECT_EQ("Hi", dest2);
+
+ const String src3("x\0y", 3);
+ const ::string dest3 = src3;
+ EXPECT_EQ(::string("x\0y", 3), dest3);
+}
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+// Tests String::ShowCStringQuoted().
+TEST(StringTest, ShowCStringQuoted) {
+ EXPECT_STREQ("(null)",
+ String::ShowCStringQuoted(NULL).c_str());
+ EXPECT_STREQ("\"\"",
+ String::ShowCStringQuoted("").c_str());
+ EXPECT_STREQ("\"foo\"",
+ String::ShowCStringQuoted("foo").c_str());
+}
+
+// Tests String::empty().
+TEST(StringTest, Empty) {
+ EXPECT_TRUE(String("").empty());
+ EXPECT_FALSE(String().empty());
+ EXPECT_FALSE(String(NULL).empty());
+ EXPECT_FALSE(String("a").empty());
+ EXPECT_FALSE(String("\0", 1).empty());
+}
+
+// Tests String::Compare().
+TEST(StringTest, Compare) {
+ // NULL vs NULL.
+ EXPECT_EQ(0, String().Compare(String()));
+
+ // NULL vs non-NULL.
+ EXPECT_EQ(-1, String().Compare(String("")));
+
+ // Non-NULL vs NULL.
+ EXPECT_EQ(1, String("").Compare(String()));
+
+ // The following covers non-NULL vs non-NULL.
+
+ // "" vs "".
+ EXPECT_EQ(0, String("").Compare(String("")));
+
+ // "" vs non-"".
+ EXPECT_EQ(-1, String("").Compare(String("\0", 1)));
+ EXPECT_EQ(-1, String("").Compare(" "));
+
+ // Non-"" vs "".
+ EXPECT_EQ(1, String("a").Compare(String("")));
+
+ // The following covers non-"" vs non-"".
+
+ // Same length and equal.
+ EXPECT_EQ(0, String("a").Compare(String("a")));
+
+ // Same length and different.
+ EXPECT_EQ(-1, String("a\0b", 3).Compare(String("a\0c", 3)));
+ EXPECT_EQ(1, String("b").Compare(String("a")));
+
+ // Different lengths.
+ EXPECT_EQ(-1, String("a").Compare(String("ab")));
+ EXPECT_EQ(-1, String("a").Compare(String("a\0", 2)));
+ EXPECT_EQ(1, String("abc").Compare(String("aacd")));
+}
+
+// Tests String::operator==().
+TEST(StringTest, Equals) {
+ const String null(NULL);
+ EXPECT_TRUE(null == NULL); // NOLINT
+ EXPECT_FALSE(null == ""); // NOLINT
+ EXPECT_FALSE(null == "bar"); // NOLINT
+
+ const String empty("");
+ EXPECT_FALSE(empty == NULL); // NOLINT
+ EXPECT_TRUE(empty == ""); // NOLINT
+ EXPECT_FALSE(empty == "bar"); // NOLINT
+
+ const String foo("foo");
+ EXPECT_FALSE(foo == NULL); // NOLINT
+ EXPECT_FALSE(foo == ""); // NOLINT
+ EXPECT_FALSE(foo == "bar"); // NOLINT
+ EXPECT_TRUE(foo == "foo"); // NOLINT
+
+ const String bar("x\0y", 3);
+ EXPECT_FALSE(bar == "x");
+}
+
+// Tests String::operator!=().
+TEST(StringTest, NotEquals) {
+ const String null(NULL);
+ EXPECT_FALSE(null != NULL); // NOLINT
+ EXPECT_TRUE(null != ""); // NOLINT
+ EXPECT_TRUE(null != "bar"); // NOLINT
+
+ const String empty("");
+ EXPECT_TRUE(empty != NULL); // NOLINT
+ EXPECT_FALSE(empty != ""); // NOLINT
+ EXPECT_TRUE(empty != "bar"); // NOLINT
+
+ const String foo("foo");
+ EXPECT_TRUE(foo != NULL); // NOLINT
+ EXPECT_TRUE(foo != ""); // NOLINT
+ EXPECT_TRUE(foo != "bar"); // NOLINT
+ EXPECT_FALSE(foo != "foo"); // NOLINT
+
+ const String bar("x\0y", 3);
+ EXPECT_TRUE(bar != "x");
+}
+
+// Tests String::length().
+TEST(StringTest, Length) {
+ EXPECT_EQ(0U, String().length());
+ EXPECT_EQ(0U, String("").length());
+ EXPECT_EQ(2U, String("ab").length());
+ EXPECT_EQ(3U, String("a\0b", 3).length());
+}
+
+// Tests String::EndsWith().
+TEST(StringTest, EndsWith) {
+ EXPECT_TRUE(String("foobar").EndsWith("bar"));
+ EXPECT_TRUE(String("foobar").EndsWith(""));
+ EXPECT_TRUE(String("").EndsWith(""));
+
+ EXPECT_FALSE(String("foobar").EndsWith("foo"));
+ EXPECT_FALSE(String("").EndsWith("foo"));
+}
+
+// Tests String::EndsWithCaseInsensitive().
+TEST(StringTest, EndsWithCaseInsensitive) {
+ EXPECT_TRUE(String("foobar").EndsWithCaseInsensitive("BAR"));
+ EXPECT_TRUE(String("foobaR").EndsWithCaseInsensitive("bar"));
+ EXPECT_TRUE(String("foobar").EndsWithCaseInsensitive(""));
+ EXPECT_TRUE(String("").EndsWithCaseInsensitive(""));
+
+ EXPECT_FALSE(String("Foobar").EndsWithCaseInsensitive("foo"));
+ EXPECT_FALSE(String("foobar").EndsWithCaseInsensitive("Foo"));
+ EXPECT_FALSE(String("").EndsWithCaseInsensitive("foo"));
+}
+
+// C++Builder's preprocessor is buggy; it fails to expand macros that
+// appear in macro parameters after wide char literals. Provide an alias
+// for NULL as a workaround.
+static const wchar_t* const kNull = NULL;
+
+// Tests String::CaseInsensitiveWideCStringEquals
+TEST(StringTest, CaseInsensitiveWideCStringEquals) {
+ EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(NULL, NULL));
+ EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L""));
+ EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"", kNull));
+ EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(kNull, L"foobar"));
+ EXPECT_FALSE(String::CaseInsensitiveWideCStringEquals(L"foobar", kNull));
+ EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"foobar"));
+ EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"foobar", L"FOOBAR"));
+ EXPECT_TRUE(String::CaseInsensitiveWideCStringEquals(L"FOOBAR", L"foobar"));
+}
+
+// Tests that NULL can be assigned to a String.
+TEST(StringTest, CanBeAssignedNULL) {
+ const String src(NULL);
+ String dest;
+
+ dest = src;
+ EXPECT_STREQ(NULL, dest.c_str());
+}
+
+// Tests that the empty string "" can be assigned to a String.
+TEST(StringTest, CanBeAssignedEmpty) {
+ const String src("");
+ String dest;
+
+ dest = src;
+ EXPECT_STREQ("", dest.c_str());
+}
+
+// Tests that a non-empty string can be assigned to a String.
+TEST(StringTest, CanBeAssignedNonEmpty) {
+ const String src("hello");
+ String dest;
+ dest = src;
+ EXPECT_EQ(5U, dest.length());
+ EXPECT_STREQ("hello", dest.c_str());
+
+ const String src2("x\0y", 3);
+ String dest2;
+ dest2 = src2;
+ EXPECT_EQ(3U, dest2.length());
+ EXPECT_EQ('x', dest2.c_str()[0]);
+ EXPECT_EQ('\0', dest2.c_str()[1]);
+ EXPECT_EQ('y', dest2.c_str()[2]);
+}
+
+// Tests that a String can be assigned to itself.
+TEST(StringTest, CanBeAssignedSelf) {
+ String dest("hello");
+
+ dest = dest;
+ EXPECT_STREQ("hello", dest.c_str());
+}
+
+// Sun Studio < 12 incorrectly rejects this code due to an overloading
+// ambiguity.
+#if !(defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
+// Tests streaming a String.
+TEST(StringTest, Streams) {
+ EXPECT_EQ(StreamableToString(String()), "(null)");
+ EXPECT_EQ(StreamableToString(String("")), "");
+ EXPECT_EQ(StreamableToString(String("a\0b", 3)), "a\\0b");
+}
+#endif
+
+// Tests that String::Format() works.
+TEST(StringTest, FormatWorks) {
+ // Normal case: the format spec is valid, the arguments match the
+ // spec, and the result is < 4095 characters.
+ EXPECT_STREQ("Hello, 42", String::Format("%s, %d", "Hello", 42).c_str());
+
+ // Edge case: the result is 4095 characters.
+ char buffer[4096];
+ const size_t kSize = sizeof(buffer);
+ memset(buffer, 'a', kSize - 1);
+ buffer[kSize - 1] = '\0';
+ EXPECT_STREQ(buffer, String::Format("%s", buffer).c_str());
+
+ // The result needs to be 4096 characters, exceeding Format()'s limit.
+ EXPECT_STREQ("<formatting error or buffer exceeded>",
+ String::Format("x%s", buffer).c_str());
+
+#if GTEST_OS_LINUX
+ // On Linux, invalid format spec should lead to an error message.
+ // In other environment (e.g. MSVC on Windows), String::Format() may
+ // simply ignore a bad format spec, so this assertion is run on
+ // Linux only.
+ EXPECT_STREQ("<formatting error or buffer exceeded>",
+ String::Format("%").c_str());
+#endif
+}
+
+#if GTEST_OS_WINDOWS
+
+// Tests String::ShowWideCString().
+TEST(StringTest, ShowWideCString) {
+ EXPECT_STREQ("(null)",
+ String::ShowWideCString(NULL).c_str());
+ EXPECT_STREQ("", String::ShowWideCString(L"").c_str());
+ EXPECT_STREQ("foo", String::ShowWideCString(L"foo").c_str());
+}
+
+// Tests String::ShowWideCStringQuoted().
+TEST(StringTest, ShowWideCStringQuoted) {
+ EXPECT_STREQ("(null)",
+ String::ShowWideCStringQuoted(NULL).c_str());
+ EXPECT_STREQ("L\"\"",
+ String::ShowWideCStringQuoted(L"").c_str());
+ EXPECT_STREQ("L\"foo\"",
+ String::ShowWideCStringQuoted(L"foo").c_str());
+}
+
+#if GTEST_OS_WINDOWS_MOBILE
+TEST(StringTest, AnsiAndUtf16Null) {
+ EXPECT_EQ(NULL, String::AnsiToUtf16(NULL));
+ EXPECT_EQ(NULL, String::Utf16ToAnsi(NULL));
+}
+
+TEST(StringTest, AnsiAndUtf16ConvertBasic) {
+ const char* ansi = String::Utf16ToAnsi(L"str");
+ EXPECT_STREQ("str", ansi);
+ delete [] ansi;
+ const WCHAR* utf16 = String::AnsiToUtf16("str");
+ EXPECT_EQ(0, wcsncmp(L"str", utf16, 3));
+ delete [] utf16;
+}
+
+TEST(StringTest, AnsiAndUtf16ConvertPathChars) {
+ const char* ansi = String::Utf16ToAnsi(L".:\\ \"*?");
+ EXPECT_STREQ(".:\\ \"*?", ansi);
+ delete [] ansi;
+ const WCHAR* utf16 = String::AnsiToUtf16(".:\\ \"*?");
+ EXPECT_EQ(0, wcsncmp(L".:\\ \"*?", utf16, 3));
+ delete [] utf16;
+}
+#endif // GTEST_OS_WINDOWS_MOBILE
+
+#endif // GTEST_OS_WINDOWS
+
+// Tests TestProperty construction.
+TEST(TestPropertyTest, StringValue) {
+ TestProperty property("key", "1");
+ EXPECT_STREQ("key", property.key());
+ EXPECT_STREQ("1", property.value());
+}
+
+// Tests TestProperty replacing a value.
+TEST(TestPropertyTest, ReplaceStringValue) {
+ TestProperty property("key", "1");
+ EXPECT_STREQ("1", property.value());
+ property.SetValue("2");
+ EXPECT_STREQ("2", property.value());
+}
+
+// AddFatalFailure() and AddNonfatalFailure() must be stand-alone
+// functions (i.e. their definitions cannot be inlined at the call
+// sites), or C++Builder won't compile the code.
+static void AddFatalFailure() {
+ FAIL() << "Expected fatal failure.";
+}
+
+static void AddNonfatalFailure() {
+ ADD_FAILURE() << "Expected non-fatal failure.";
+}
+
+class ScopedFakeTestPartResultReporterTest : public Test {
+ public: // Must be public and not protected due to a bug in g++ 3.4.2.
+ enum FailureMode {
+ FATAL_FAILURE,
+ NONFATAL_FAILURE
+ };
+ static void AddFailure(FailureMode failure) {
+ if (failure == FATAL_FAILURE) {
+ AddFatalFailure();
+ } else {
+ AddNonfatalFailure();
+ }
+ }
+};
+
+// Tests that ScopedFakeTestPartResultReporter intercepts test
+// failures.
+TEST_F(ScopedFakeTestPartResultReporterTest, InterceptsTestFailures) {
+ TestPartResultArray results;
+ {
+ ScopedFakeTestPartResultReporter reporter(
+ ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD,
+ &results);
+ AddFailure(NONFATAL_FAILURE);
+ AddFailure(FATAL_FAILURE);
+ }
+
+ EXPECT_EQ(2, results.size());
+ EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed());
+ EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed());
+}
+
+TEST_F(ScopedFakeTestPartResultReporterTest, DeprecatedConstructor) {
+ TestPartResultArray results;
+ {
+ // Tests, that the deprecated constructor still works.
+ ScopedFakeTestPartResultReporter reporter(&results);
+ AddFailure(NONFATAL_FAILURE);
+ }
+ EXPECT_EQ(1, results.size());
+}
+
+#if GTEST_IS_THREADSAFE
+
+class ScopedFakeTestPartResultReporterWithThreadsTest
+ : public ScopedFakeTestPartResultReporterTest {
+ protected:
+ static void AddFailureInOtherThread(FailureMode failure) {
+ ThreadWithParam<FailureMode> thread(&AddFailure, failure, NULL);
+ thread.Join();
+ }
+};
+
+TEST_F(ScopedFakeTestPartResultReporterWithThreadsTest,
+ InterceptsTestFailuresInAllThreads) {
+ TestPartResultArray results;
+ {
+ ScopedFakeTestPartResultReporter reporter(
+ ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, &results);
+ AddFailure(NONFATAL_FAILURE);
+ AddFailure(FATAL_FAILURE);
+ AddFailureInOtherThread(NONFATAL_FAILURE);
+ AddFailureInOtherThread(FATAL_FAILURE);
+ }
+
+ EXPECT_EQ(4, results.size());
+ EXPECT_TRUE(results.GetTestPartResult(0).nonfatally_failed());
+ EXPECT_TRUE(results.GetTestPartResult(1).fatally_failed());
+ EXPECT_TRUE(results.GetTestPartResult(2).nonfatally_failed());
+ EXPECT_TRUE(results.GetTestPartResult(3).fatally_failed());
+}
+
+#endif // GTEST_IS_THREADSAFE
+
+// Tests EXPECT_FATAL_FAILURE{,ON_ALL_THREADS}. Makes sure that they
+// work even if the failure is generated in a called function rather than
+// the current context.
+
+typedef ScopedFakeTestPartResultReporterTest ExpectFatalFailureTest;
+
+TEST_F(ExpectFatalFailureTest, CatchesFatalFaliure) {
+ EXPECT_FATAL_FAILURE(AddFatalFailure(), "Expected fatal failure.");
+}
+
+TEST_F(ExpectFatalFailureTest, CatchesFatalFailureOnAllThreads) {
+ // We have another test below to verify that the macro catches fatal
+ // failures generated on another thread.
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFatalFailure(),
+ "Expected fatal failure.");
+}
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true"
+#pragma option push -w-ccc
+#endif
+
+// Tests that EXPECT_FATAL_FAILURE() can be used in a non-void
+// function even when the statement in it contains ASSERT_*.
+
+int NonVoidFunction() {
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), "");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), "");
+ return 0;
+}
+
+TEST_F(ExpectFatalFailureTest, CanBeUsedInNonVoidFunction) {
+ NonVoidFunction();
+}
+
+// Tests that EXPECT_FATAL_FAILURE(statement, ...) doesn't abort the
+// current function even though 'statement' generates a fatal failure.
+
+void DoesNotAbortHelper(bool* aborted) {
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(false), "");
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(FAIL(), "");
+
+ *aborted = false;
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" suppressed them.
+#pragma option pop
+#endif
+
+TEST_F(ExpectFatalFailureTest, DoesNotAbort) {
+ bool aborted = true;
+ DoesNotAbortHelper(&aborted);
+ EXPECT_FALSE(aborted);
+}
+
+// Tests that the EXPECT_FATAL_FAILURE{,_ON_ALL_THREADS} accepts a
+// statement that contains a macro which expands to code containing an
+// unprotected comma.
+
+static int global_var = 0;
+#define GTEST_USE_UNPROTECTED_COMMA_ global_var++, global_var++
+
+TEST_F(ExpectFatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) {
+#if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600
+ // ICE's in C++Builder 2007.
+ EXPECT_FATAL_FAILURE({
+ GTEST_USE_UNPROTECTED_COMMA_;
+ AddFatalFailure();
+ }, "");
+#endif
+
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS({
+ GTEST_USE_UNPROTECTED_COMMA_;
+ AddFatalFailure();
+ }, "");
+}
+
+// Tests EXPECT_NONFATAL_FAILURE{,ON_ALL_THREADS}.
+
+typedef ScopedFakeTestPartResultReporterTest ExpectNonfatalFailureTest;
+
+TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailure) {
+ EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(),
+ "Expected non-fatal failure.");
+}
+
+TEST_F(ExpectNonfatalFailureTest, CatchesNonfatalFailureOnAllThreads) {
+ // We have another test below to verify that the macro catches
+ // non-fatal failures generated on another thread.
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(AddNonfatalFailure(),
+ "Expected non-fatal failure.");
+}
+
+// Tests that the EXPECT_NONFATAL_FAILURE{,_ON_ALL_THREADS} accepts a
+// statement that contains a macro which expands to code containing an
+// unprotected comma.
+TEST_F(ExpectNonfatalFailureTest, AcceptsMacroThatExpandsToUnprotectedComma) {
+ EXPECT_NONFATAL_FAILURE({
+ GTEST_USE_UNPROTECTED_COMMA_;
+ AddNonfatalFailure();
+ }, "");
+
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS({
+ GTEST_USE_UNPROTECTED_COMMA_;
+ AddNonfatalFailure();
+ }, "");
+}
+
+#if GTEST_IS_THREADSAFE
+
+typedef ScopedFakeTestPartResultReporterWithThreadsTest
+ ExpectFailureWithThreadsTest;
+
+TEST_F(ExpectFailureWithThreadsTest, ExpectFatalFailureOnAllThreads) {
+ EXPECT_FATAL_FAILURE_ON_ALL_THREADS(AddFailureInOtherThread(FATAL_FAILURE),
+ "Expected fatal failure.");
+}
+
+TEST_F(ExpectFailureWithThreadsTest, ExpectNonFatalFailureOnAllThreads) {
+ EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(
+ AddFailureInOtherThread(NONFATAL_FAILURE), "Expected non-fatal failure.");
+}
+
+#endif // GTEST_IS_THREADSAFE
+
+// Tests the TestProperty class.
+
+TEST(TestPropertyTest, ConstructorWorks) {
+ const TestProperty property("key", "value");
+ EXPECT_STREQ("key", property.key());
+ EXPECT_STREQ("value", property.value());
+}
+
+TEST(TestPropertyTest, SetValue) {
+ TestProperty property("key", "value_1");
+ EXPECT_STREQ("key", property.key());
+ property.SetValue("value_2");
+ EXPECT_STREQ("key", property.key());
+ EXPECT_STREQ("value_2", property.value());
+}
+
+// Tests the TestResult class
+
+// The test fixture for testing TestResult.
+class TestResultTest : public Test {
+ protected:
+ typedef std::vector<TestPartResult> TPRVector;
+
+ // We make use of 2 TestPartResult objects,
+ TestPartResult * pr1, * pr2;
+
+ // ... and 3 TestResult objects.
+ TestResult * r0, * r1, * r2;
+
+ virtual void SetUp() {
+ // pr1 is for success.
+ pr1 = new TestPartResult(TestPartResult::kSuccess,
+ "foo/bar.cc",
+ 10,
+ "Success!");
+
+ // pr2 is for fatal failure.
+ pr2 = new TestPartResult(TestPartResult::kFatalFailure,
+ "foo/bar.cc",
+ -1, // This line number means "unknown"
+ "Failure!");
+
+ // Creates the TestResult objects.
+ r0 = new TestResult();
+ r1 = new TestResult();
+ r2 = new TestResult();
+
+ // In order to test TestResult, we need to modify its internal
+ // state, in particular the TestPartResult vector it holds.
+ // test_part_results() returns a const reference to this vector.
+ // We cast it to a non-const object s.t. it can be modified (yes,
+ // this is a hack).
+ TPRVector* results1 = const_cast<TPRVector*>(
+ &TestResultAccessor::test_part_results(*r1));
+ TPRVector* results2 = const_cast<TPRVector*>(
+ &TestResultAccessor::test_part_results(*r2));
+
+ // r0 is an empty TestResult.
+
+ // r1 contains a single SUCCESS TestPartResult.
+ results1->push_back(*pr1);
+
+ // r2 contains a SUCCESS, and a FAILURE.
+ results2->push_back(*pr1);
+ results2->push_back(*pr2);
+ }
+
+ virtual void TearDown() {
+ delete pr1;
+ delete pr2;
+
+ delete r0;
+ delete r1;
+ delete r2;
+ }
+
+ // Helper that compares two two TestPartResults.
+ static void CompareTestPartResult(const TestPartResult& expected,
+ const TestPartResult& actual) {
+ EXPECT_EQ(expected.type(), actual.type());
+ EXPECT_STREQ(expected.file_name(), actual.file_name());
+ EXPECT_EQ(expected.line_number(), actual.line_number());
+ EXPECT_STREQ(expected.summary(), actual.summary());
+ EXPECT_STREQ(expected.message(), actual.message());
+ EXPECT_EQ(expected.passed(), actual.passed());
+ EXPECT_EQ(expected.failed(), actual.failed());
+ EXPECT_EQ(expected.nonfatally_failed(), actual.nonfatally_failed());
+ EXPECT_EQ(expected.fatally_failed(), actual.fatally_failed());
+ }
+};
+
+// Tests TestResult::total_part_count().
+TEST_F(TestResultTest, total_part_count) {
+ ASSERT_EQ(0, r0->total_part_count());
+ ASSERT_EQ(1, r1->total_part_count());
+ ASSERT_EQ(2, r2->total_part_count());
+}
+
+// Tests TestResult::Passed().
+TEST_F(TestResultTest, Passed) {
+ ASSERT_TRUE(r0->Passed());
+ ASSERT_TRUE(r1->Passed());
+ ASSERT_FALSE(r2->Passed());
+}
+
+// Tests TestResult::Failed().
+TEST_F(TestResultTest, Failed) {
+ ASSERT_FALSE(r0->Failed());
+ ASSERT_FALSE(r1->Failed());
+ ASSERT_TRUE(r2->Failed());
+}
+
+// Tests TestResult::GetTestPartResult().
+
+typedef TestResultTest TestResultDeathTest;
+
+TEST_F(TestResultDeathTest, GetTestPartResult) {
+ CompareTestPartResult(*pr1, r2->GetTestPartResult(0));
+ CompareTestPartResult(*pr2, r2->GetTestPartResult(1));
+ EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(2), "");
+ EXPECT_DEATH_IF_SUPPORTED(r2->GetTestPartResult(-1), "");
+}
+
+// Tests TestResult has no properties when none are added.
+TEST(TestResultPropertyTest, NoPropertiesFoundWhenNoneAreAdded) {
+ TestResult test_result;
+ ASSERT_EQ(0, test_result.test_property_count());
+}
+
+// Tests TestResult has the expected property when added.
+TEST(TestResultPropertyTest, OnePropertyFoundWhenAdded) {
+ TestResult test_result;
+ TestProperty property("key_1", "1");
+ TestResultAccessor::RecordProperty(&test_result, property);
+ ASSERT_EQ(1, test_result.test_property_count());
+ const TestProperty& actual_property = test_result.GetTestProperty(0);
+ EXPECT_STREQ("key_1", actual_property.key());
+ EXPECT_STREQ("1", actual_property.value());
+}
+
+// Tests TestResult has multiple properties when added.
+TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded) {
+ TestResult test_result;
+ TestProperty property_1("key_1", "1");
+ TestProperty property_2("key_2", "2");
+ TestResultAccessor::RecordProperty(&test_result, property_1);
+ TestResultAccessor::RecordProperty(&test_result, property_2);
+ ASSERT_EQ(2, test_result.test_property_count());
+ const TestProperty& actual_property_1 = test_result.GetTestProperty(0);
+ EXPECT_STREQ("key_1", actual_property_1.key());
+ EXPECT_STREQ("1", actual_property_1.value());
+
+ const TestProperty& actual_property_2 = test_result.GetTestProperty(1);
+ EXPECT_STREQ("key_2", actual_property_2.key());
+ EXPECT_STREQ("2", actual_property_2.value());
+}
+
+// Tests TestResult::RecordProperty() overrides values for duplicate keys.
+TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) {
+ TestResult test_result;
+ TestProperty property_1_1("key_1", "1");
+ TestProperty property_2_1("key_2", "2");
+ TestProperty property_1_2("key_1", "12");
+ TestProperty property_2_2("key_2", "22");
+ TestResultAccessor::RecordProperty(&test_result, property_1_1);
+ TestResultAccessor::RecordProperty(&test_result, property_2_1);
+ TestResultAccessor::RecordProperty(&test_result, property_1_2);
+ TestResultAccessor::RecordProperty(&test_result, property_2_2);
+
+ ASSERT_EQ(2, test_result.test_property_count());
+ const TestProperty& actual_property_1 = test_result.GetTestProperty(0);
+ EXPECT_STREQ("key_1", actual_property_1.key());
+ EXPECT_STREQ("12", actual_property_1.value());
+
+ const TestProperty& actual_property_2 = test_result.GetTestProperty(1);
+ EXPECT_STREQ("key_2", actual_property_2.key());
+ EXPECT_STREQ("22", actual_property_2.value());
+}
+
+// Tests TestResult::GetTestProperty().
+TEST(TestResultPropertyDeathTest, GetTestProperty) {
+ TestResult test_result;
+ TestProperty property_1("key_1", "1");
+ TestProperty property_2("key_2", "2");
+ TestProperty property_3("key_3", "3");
+ TestResultAccessor::RecordProperty(&test_result, property_1);
+ TestResultAccessor::RecordProperty(&test_result, property_2);
+ TestResultAccessor::RecordProperty(&test_result, property_3);
+
+ const TestProperty& fetched_property_1 = test_result.GetTestProperty(0);
+ const TestProperty& fetched_property_2 = test_result.GetTestProperty(1);
+ const TestProperty& fetched_property_3 = test_result.GetTestProperty(2);
+
+ EXPECT_STREQ("key_1", fetched_property_1.key());
+ EXPECT_STREQ("1", fetched_property_1.value());
+
+ EXPECT_STREQ("key_2", fetched_property_2.key());
+ EXPECT_STREQ("2", fetched_property_2.value());
+
+ EXPECT_STREQ("key_3", fetched_property_3.key());
+ EXPECT_STREQ("3", fetched_property_3.value());
+
+ EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(3), "");
+ EXPECT_DEATH_IF_SUPPORTED(test_result.GetTestProperty(-1), "");
+}
+
+// When a property using a reserved key is supplied to this function, it tests
+// that a non-fatal failure is added, a fatal failure is not added, and that the
+// property is not recorded.
+void ExpectNonFatalFailureRecordingPropertyWithReservedKey(const char* key) {
+ TestResult test_result;
+ TestProperty property(key, "1");
+ EXPECT_NONFATAL_FAILURE(
+ TestResultAccessor::RecordProperty(&test_result, property),
+ "Reserved key");
+ ASSERT_EQ(0, test_result.test_property_count()) << "Not recorded";
+}
+
+// Attempting to recording a property with the Reserved literal "name"
+// should add a non-fatal failure and the property should not be recorded.
+TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledName) {
+ ExpectNonFatalFailureRecordingPropertyWithReservedKey("name");
+}
+
+// Attempting to recording a property with the Reserved literal "status"
+// should add a non-fatal failure and the property should not be recorded.
+TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledStatus) {
+ ExpectNonFatalFailureRecordingPropertyWithReservedKey("status");
+}
+
+// Attempting to recording a property with the Reserved literal "time"
+// should add a non-fatal failure and the property should not be recorded.
+TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledTime) {
+ ExpectNonFatalFailureRecordingPropertyWithReservedKey("time");
+}
+
+// Attempting to recording a property with the Reserved literal "classname"
+// should add a non-fatal failure and the property should not be recorded.
+TEST(TestResultPropertyTest, AddFailureWhenUsingReservedKeyCalledClassname) {
+ ExpectNonFatalFailureRecordingPropertyWithReservedKey("classname");
+}
+
+// Tests that GTestFlagSaver works on Windows and Mac.
+
+class GTestFlagSaverTest : public Test {
+ protected:
+ // Saves the Google Test flags such that we can restore them later, and
+ // then sets them to their default values. This will be called
+ // before the first test in this test case is run.
+ static void SetUpTestCase() {
+ saver_ = new GTestFlagSaver;
+
+ GTEST_FLAG(also_run_disabled_tests) = false;
+ GTEST_FLAG(break_on_failure) = false;
+ GTEST_FLAG(catch_exceptions) = false;
+ GTEST_FLAG(death_test_use_fork) = false;
+ GTEST_FLAG(color) = "auto";
+ GTEST_FLAG(filter) = "";
+ GTEST_FLAG(list_tests) = false;
+ GTEST_FLAG(output) = "";
+ GTEST_FLAG(print_time) = true;
+ GTEST_FLAG(random_seed) = 0;
+ GTEST_FLAG(repeat) = 1;
+ GTEST_FLAG(shuffle) = false;
+ GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth;
+ GTEST_FLAG(throw_on_failure) = false;
+ }
+
+ // Restores the Google Test flags that the tests have modified. This will
+ // be called after the last test in this test case is run.
+ static void TearDownTestCase() {
+ delete saver_;
+ saver_ = NULL;
+ }
+
+ // Verifies that the Google Test flags have their default values, and then
+ // modifies each of them.
+ void VerifyAndModifyFlags() {
+ EXPECT_FALSE(GTEST_FLAG(also_run_disabled_tests));
+ EXPECT_FALSE(GTEST_FLAG(break_on_failure));
+ EXPECT_FALSE(GTEST_FLAG(catch_exceptions));
+ EXPECT_STREQ("auto", GTEST_FLAG(color).c_str());
+ EXPECT_FALSE(GTEST_FLAG(death_test_use_fork));
+ EXPECT_STREQ("", GTEST_FLAG(filter).c_str());
+ EXPECT_FALSE(GTEST_FLAG(list_tests));
+ EXPECT_STREQ("", GTEST_FLAG(output).c_str());
+ EXPECT_TRUE(GTEST_FLAG(print_time));
+ EXPECT_EQ(0, GTEST_FLAG(random_seed));
+ EXPECT_EQ(1, GTEST_FLAG(repeat));
+ EXPECT_FALSE(GTEST_FLAG(shuffle));
+ EXPECT_EQ(kMaxStackTraceDepth, GTEST_FLAG(stack_trace_depth));
+ EXPECT_FALSE(GTEST_FLAG(throw_on_failure));
+
+ GTEST_FLAG(also_run_disabled_tests) = true;
+ GTEST_FLAG(break_on_failure) = true;
+ GTEST_FLAG(catch_exceptions) = true;
+ GTEST_FLAG(color) = "no";
+ GTEST_FLAG(death_test_use_fork) = true;
+ GTEST_FLAG(filter) = "abc";
+ GTEST_FLAG(list_tests) = true;
+ GTEST_FLAG(output) = "xml:foo.xml";
+ GTEST_FLAG(print_time) = false;
+ GTEST_FLAG(random_seed) = 1;
+ GTEST_FLAG(repeat) = 100;
+ GTEST_FLAG(shuffle) = true;
+ GTEST_FLAG(stack_trace_depth) = 1;
+ GTEST_FLAG(throw_on_failure) = true;
+ }
+ private:
+ // For saving Google Test flags during this test case.
+ static GTestFlagSaver* saver_;
+};
+
+GTestFlagSaver* GTestFlagSaverTest::saver_ = NULL;
+
+// Google Test doesn't guarantee the order of tests. The following two
+// tests are designed to work regardless of their order.
+
+// Modifies the Google Test flags in the test body.
+TEST_F(GTestFlagSaverTest, ModifyGTestFlags) {
+ VerifyAndModifyFlags();
+}
+
+// Verifies that the Google Test flags in the body of the previous test were
+// restored to their original values.
+TEST_F(GTestFlagSaverTest, VerifyGTestFlags) {
+ VerifyAndModifyFlags();
+}
+
+// Sets an environment variable with the given name to the given
+// value. If the value argument is "", unsets the environment
+// variable. The caller must ensure that both arguments are not NULL.
+static void SetEnv(const char* name, const char* value) {
+#if GTEST_OS_WINDOWS_MOBILE
+ // Environment variables are not supported on Windows CE.
+ return;
+#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
+ // C++Builder's putenv only stores a pointer to its parameter; we have to
+ // ensure that the string remains valid as long as it might be needed.
+ // We use an std::map to do so.
+ static std::map<String, String*> added_env;
+
+ // Because putenv stores a pointer to the string buffer, we can't delete the
+ // previous string (if present) until after it's replaced.
+ String *prev_env = NULL;
+ if (added_env.find(name) != added_env.end()) {
+ prev_env = added_env[name];
+ }
+ added_env[name] = new String((Message() << name << "=" << value).GetString());
+
+ // The standard signature of putenv accepts a 'char*' argument. Other
+ // implementations, like C++Builder's, accept a 'const char*'.
+ // We cast away the 'const' since that would work for both variants.
+ putenv(const_cast<char*>(added_env[name]->c_str()));
+ delete prev_env;
+#elif GTEST_OS_WINDOWS // If we are on Windows proper.
+ _putenv((Message() << name << "=" << value).GetString().c_str());
+#else
+ if (*value == '\0') {
+ unsetenv(name);
+ } else {
+ setenv(name, value, 1);
+ }
+#endif // GTEST_OS_WINDOWS_MOBILE
+}
+
+#if !GTEST_OS_WINDOWS_MOBILE
+// Environment variables are not supported on Windows CE.
+
+using testing::internal::Int32FromGTestEnv;
+
+// Tests Int32FromGTestEnv().
+
+// Tests that Int32FromGTestEnv() returns the default value when the
+// environment variable is not set.
+TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenVariableIsNotSet) {
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "");
+ EXPECT_EQ(10, Int32FromGTestEnv("temp", 10));
+}
+
+// Tests that Int32FromGTestEnv() returns the default value when the
+// environment variable overflows as an Int32.
+TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueOverflows) {
+ printf("(expecting 2 warnings)\n");
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12345678987654321");
+ EXPECT_EQ(20, Int32FromGTestEnv("temp", 20));
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-12345678987654321");
+ EXPECT_EQ(30, Int32FromGTestEnv("temp", 30));
+}
+
+// Tests that Int32FromGTestEnv() returns the default value when the
+// environment variable does not represent a valid decimal integer.
+TEST(Int32FromGTestEnvTest, ReturnsDefaultWhenValueIsInvalid) {
+ printf("(expecting 2 warnings)\n");
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "A1");
+ EXPECT_EQ(40, Int32FromGTestEnv("temp", 40));
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "12X");
+ EXPECT_EQ(50, Int32FromGTestEnv("temp", 50));
+}
+
+// Tests that Int32FromGTestEnv() parses and returns the value of the
+// environment variable when it represents a valid decimal integer in
+// the range of an Int32.
+TEST(Int32FromGTestEnvTest, ParsesAndReturnsValidValue) {
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "123");
+ EXPECT_EQ(123, Int32FromGTestEnv("temp", 0));
+
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "TEMP", "-321");
+ EXPECT_EQ(-321, Int32FromGTestEnv("temp", 0));
+}
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+// Tests ParseInt32Flag().
+
+// Tests that ParseInt32Flag() returns false and doesn't change the
+// output value when the flag has wrong format
+TEST(ParseInt32FlagTest, ReturnsFalseForInvalidFlag) {
+ Int32 value = 123;
+ EXPECT_FALSE(ParseInt32Flag("--a=100", "b", &value));
+ EXPECT_EQ(123, value);
+
+ EXPECT_FALSE(ParseInt32Flag("a=100", "a", &value));
+ EXPECT_EQ(123, value);
+}
+
+// Tests that ParseInt32Flag() returns false and doesn't change the
+// output value when the flag overflows as an Int32.
+TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueOverflows) {
+ printf("(expecting 2 warnings)\n");
+
+ Int32 value = 123;
+ EXPECT_FALSE(ParseInt32Flag("--abc=12345678987654321", "abc", &value));
+ EXPECT_EQ(123, value);
+
+ EXPECT_FALSE(ParseInt32Flag("--abc=-12345678987654321", "abc", &value));
+ EXPECT_EQ(123, value);
+}
+
+// Tests that ParseInt32Flag() returns false and doesn't change the
+// output value when the flag does not represent a valid decimal
+// integer.
+TEST(ParseInt32FlagTest, ReturnsDefaultWhenValueIsInvalid) {
+ printf("(expecting 2 warnings)\n");
+
+ Int32 value = 123;
+ EXPECT_FALSE(ParseInt32Flag("--abc=A1", "abc", &value));
+ EXPECT_EQ(123, value);
+
+ EXPECT_FALSE(ParseInt32Flag("--abc=12X", "abc", &value));
+ EXPECT_EQ(123, value);
+}
+
+// Tests that ParseInt32Flag() parses the value of the flag and
+// returns true when the flag represents a valid decimal integer in
+// the range of an Int32.
+TEST(ParseInt32FlagTest, ParsesAndReturnsValidValue) {
+ Int32 value = 123;
+ EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=456", "abc", &value));
+ EXPECT_EQ(456, value);
+
+ EXPECT_TRUE(ParseInt32Flag("--" GTEST_FLAG_PREFIX_ "abc=-789",
+ "abc", &value));
+ EXPECT_EQ(-789, value);
+}
+
+// Tests that Int32FromEnvOrDie() parses the value of the var or
+// returns the correct default.
+// Environment variables are not supported on Windows CE.
+#if !GTEST_OS_WINDOWS_MOBILE
+TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) {
+ EXPECT_EQ(333, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333));
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "123");
+ EXPECT_EQ(123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333));
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "-123");
+ EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333));
+}
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+// Tests that Int32FromEnvOrDie() aborts with an error message
+// if the variable is not an Int32.
+TEST(Int32FromEnvOrDieDeathTest, AbortsOnFailure) {
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "xxx");
+ EXPECT_DEATH_IF_SUPPORTED(
+ Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123),
+ ".*");
+}
+
+// Tests that Int32FromEnvOrDie() aborts with an error message
+// if the variable cannot be represnted by an Int32.
+TEST(Int32FromEnvOrDieDeathTest, AbortsOnInt32Overflow) {
+ SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "1234567891234567891234");
+ EXPECT_DEATH_IF_SUPPORTED(
+ Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123),
+ ".*");
+}
+
+// Tests that ShouldRunTestOnShard() selects all tests
+// where there is 1 shard.
+TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereIsOneShard) {
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 0));
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 1));
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 2));
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 3));
+ EXPECT_TRUE(ShouldRunTestOnShard(1, 0, 4));
+}
+
+class ShouldShardTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ index_var_ = GTEST_FLAG_PREFIX_UPPER_ "INDEX";
+ total_var_ = GTEST_FLAG_PREFIX_UPPER_ "TOTAL";
+ }
+
+ virtual void TearDown() {
+ SetEnv(index_var_, "");
+ SetEnv(total_var_, "");
+ }
+
+ const char* index_var_;
+ const char* total_var_;
+};
+
+// Tests that sharding is disabled if neither of the environment variables
+// are set.
+TEST_F(ShouldShardTest, ReturnsFalseWhenNeitherEnvVarIsSet) {
+ SetEnv(index_var_, "");
+ SetEnv(total_var_, "");
+
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+}
+
+// Tests that sharding is not enabled if total_shards == 1.
+TEST_F(ShouldShardTest, ReturnsFalseWhenTotalShardIsOne) {
+ SetEnv(index_var_, "0");
+ SetEnv(total_var_, "1");
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+}
+
+// Tests that sharding is enabled if total_shards > 1 and
+// we are not in a death test subprocess.
+// Environment variables are not supported on Windows CE.
+#if !GTEST_OS_WINDOWS_MOBILE
+TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) {
+ SetEnv(index_var_, "4");
+ SetEnv(total_var_, "22");
+ EXPECT_TRUE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+
+ SetEnv(index_var_, "8");
+ SetEnv(total_var_, "9");
+ EXPECT_TRUE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+
+ SetEnv(index_var_, "0");
+ SetEnv(total_var_, "9");
+ EXPECT_TRUE(ShouldShard(total_var_, index_var_, false));
+ EXPECT_FALSE(ShouldShard(total_var_, index_var_, true));
+}
+#endif // !GTEST_OS_WINDOWS_MOBILE
+
+// Tests that we exit in error if the sharding values are not valid.
+
+typedef ShouldShardTest ShouldShardDeathTest;
+
+TEST_F(ShouldShardDeathTest, AbortsWhenShardingEnvVarsAreInvalid) {
+ SetEnv(index_var_, "4");
+ SetEnv(total_var_, "4");
+ EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*");
+
+ SetEnv(index_var_, "4");
+ SetEnv(total_var_, "-2");
+ EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*");
+
+ SetEnv(index_var_, "5");
+ SetEnv(total_var_, "");
+ EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*");
+
+ SetEnv(index_var_, "");
+ SetEnv(total_var_, "5");
+ EXPECT_DEATH_IF_SUPPORTED(ShouldShard(total_var_, index_var_, false), ".*");
+}
+
+// Tests that ShouldRunTestOnShard is a partition when 5
+// shards are used.
+TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereAreFiveShards) {
+ // Choose an arbitrary number of tests and shards.
+ const int num_tests = 17;
+ const int num_shards = 5;
+
+ // Check partitioning: each test should be on exactly 1 shard.
+ for (int test_id = 0; test_id < num_tests; test_id++) {
+ int prev_selected_shard_index = -1;
+ for (int shard_index = 0; shard_index < num_shards; shard_index++) {
+ if (ShouldRunTestOnShard(num_shards, shard_index, test_id)) {
+ if (prev_selected_shard_index < 0) {
+ prev_selected_shard_index = shard_index;
+ } else {
+ ADD_FAILURE() << "Shard " << prev_selected_shard_index << " and "
+ << shard_index << " are both selected to run test " << test_id;
+ }
+ }
+ }
+ }
+
+ // Check balance: This is not required by the sharding protocol, but is a
+ // desirable property for performance.
+ for (int shard_index = 0; shard_index < num_shards; shard_index++) {
+ int num_tests_on_shard = 0;
+ for (int test_id = 0; test_id < num_tests; test_id++) {
+ num_tests_on_shard +=
+ ShouldRunTestOnShard(num_shards, shard_index, test_id);
+ }
+ EXPECT_GE(num_tests_on_shard, num_tests / num_shards);
+ }
+}
+
+// For the same reason we are not explicitly testing everything in the
+// Test class, there are no separate tests for the following classes
+// (except for some trivial cases):
+//
+// TestCase, UnitTest, UnitTestResultPrinter.
+//
+// Similarly, there are no separate tests for the following macros:
+//
+// TEST, TEST_F, RUN_ALL_TESTS
+
+TEST(UnitTestTest, CanGetOriginalWorkingDir) {
+ ASSERT_TRUE(UnitTest::GetInstance()->original_working_dir() != NULL);
+ EXPECT_STRNE(UnitTest::GetInstance()->original_working_dir(), "");
+}
+
+// This group of tests is for predicate assertions (ASSERT_PRED*, etc)
+// of various arities. They do not attempt to be exhaustive. Rather,
+// view them as smoke tests that can be easily reviewed and verified.
+// A more complete set of tests for predicate assertions can be found
+// in gtest_pred_impl_unittest.cc.
+
+// First, some predicates and predicate-formatters needed by the tests.
+
+// Returns true iff the argument is an even number.
+bool IsEven(int n) {
+ return (n % 2) == 0;
+}
+
+// A functor that returns true iff the argument is an even number.
+struct IsEvenFunctor {
+ bool operator()(int n) { return IsEven(n); }
+};
+
+// A predicate-formatter function that asserts the argument is an even
+// number.
+AssertionResult AssertIsEven(const char* expr, int n) {
+ if (IsEven(n)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << expr << " evaluates to " << n << ", which is not even.";
+ return AssertionFailure(msg);
+}
+
+// A predicate function that returns AssertionResult for use in
+// EXPECT/ASSERT_TRUE/FALSE.
+AssertionResult ResultIsEven(int n) {
+ if (IsEven(n))
+ return AssertionSuccess() << n << " is even";
+ else
+ return AssertionFailure() << n << " is odd";
+}
+
+// A predicate function that returns AssertionResult but gives no
+// explanation why it succeeds. Needed for testing that
+// EXPECT/ASSERT_FALSE handles such functions correctly.
+AssertionResult ResultIsEvenNoExplanation(int n) {
+ if (IsEven(n))
+ return AssertionSuccess();
+ else
+ return AssertionFailure() << n << " is odd";
+}
+
+// A predicate-formatter functor that asserts the argument is an even
+// number.
+struct AssertIsEvenFunctor {
+ AssertionResult operator()(const char* expr, int n) {
+ return AssertIsEven(expr, n);
+ }
+};
+
+// Returns true iff the sum of the arguments is an even number.
+bool SumIsEven2(int n1, int n2) {
+ return IsEven(n1 + n2);
+}
+
+// A functor that returns true iff the sum of the arguments is an even
+// number.
+struct SumIsEven3Functor {
+ bool operator()(int n1, int n2, int n3) {
+ return IsEven(n1 + n2 + n3);
+ }
+};
+
+// A predicate-formatter function that asserts the sum of the
+// arguments is an even number.
+AssertionResult AssertSumIsEven4(
+ const char* e1, const char* e2, const char* e3, const char* e4,
+ int n1, int n2, int n3, int n4) {
+ const int sum = n1 + n2 + n3 + n4;
+ if (IsEven(sum)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << e1 << " + " << e2 << " + " << e3 << " + " << e4
+ << " (" << n1 << " + " << n2 << " + " << n3 << " + " << n4
+ << ") evaluates to " << sum << ", which is not even.";
+ return AssertionFailure(msg);
+}
+
+// A predicate-formatter functor that asserts the sum of the arguments
+// is an even number.
+struct AssertSumIsEven5Functor {
+ AssertionResult operator()(
+ const char* e1, const char* e2, const char* e3, const char* e4,
+ const char* e5, int n1, int n2, int n3, int n4, int n5) {
+ const int sum = n1 + n2 + n3 + n4 + n5;
+ if (IsEven(sum)) {
+ return AssertionSuccess();
+ }
+
+ Message msg;
+ msg << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5
+ << " ("
+ << n1 << " + " << n2 << " + " << n3 << " + " << n4 << " + " << n5
+ << ") evaluates to " << sum << ", which is not even.";
+ return AssertionFailure(msg);
+ }
+};
+
+
+// Tests unary predicate assertions.
+
+// Tests unary predicate assertions that don't use a custom formatter.
+TEST(Pred1Test, WithoutFormat) {
+ // Success cases.
+ EXPECT_PRED1(IsEvenFunctor(), 2) << "This failure is UNEXPECTED!";
+ ASSERT_PRED1(IsEven, 4);
+
+ // Failure cases.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED1(IsEven, 5) << "This failure is expected.";
+ }, "This failure is expected.");
+ EXPECT_FATAL_FAILURE(ASSERT_PRED1(IsEvenFunctor(), 5),
+ "evaluates to false");
+}
+
+// Tests unary predicate assertions that use a custom formatter.
+TEST(Pred1Test, WithFormat) {
+ // Success cases.
+ EXPECT_PRED_FORMAT1(AssertIsEven, 2);
+ ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), 4)
+ << "This failure is UNEXPECTED!";
+
+ // Failure cases.
+ const int n = 5;
+ EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT1(AssertIsEvenFunctor(), n),
+ "n evaluates to 5, which is not even.");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(AssertIsEven, 5) << "This failure is expected.";
+ }, "This failure is expected.");
+}
+
+// Tests that unary predicate assertions evaluates their arguments
+// exactly once.
+TEST(Pred1Test, SingleEvaluationOnFailure) {
+ // A success case.
+ static int n = 0;
+ EXPECT_PRED1(IsEven, n++);
+ EXPECT_EQ(1, n) << "The argument is not evaluated exactly once.";
+
+ // A failure case.
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT1(AssertIsEvenFunctor(), n++)
+ << "This failure is expected.";
+ }, "This failure is expected.");
+ EXPECT_EQ(2, n) << "The argument is not evaluated exactly once.";
+}
+
+
+// Tests predicate assertions whose arity is >= 2.
+
+// Tests predicate assertions that don't use a custom formatter.
+TEST(PredTest, WithoutFormat) {
+ // Success cases.
+ ASSERT_PRED2(SumIsEven2, 2, 4) << "This failure is UNEXPECTED!";
+ EXPECT_PRED3(SumIsEven3Functor(), 4, 6, 8);
+
+ // Failure cases.
+ const int n1 = 1;
+ const int n2 = 2;
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED2(SumIsEven2, n1, n2) << "This failure is expected.";
+ }, "This failure is expected.");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED3(SumIsEven3Functor(), 1, 2, 4);
+ }, "evaluates to false");
+}
+
+// Tests predicate assertions that use a custom formatter.
+TEST(PredTest, WithFormat) {
+ // Success cases.
+ ASSERT_PRED_FORMAT4(AssertSumIsEven4, 4, 6, 8, 10) <<
+ "This failure is UNEXPECTED!";
+ EXPECT_PRED_FORMAT5(AssertSumIsEven5Functor(), 2, 4, 6, 8, 10);
+
+ // Failure cases.
+ const int n1 = 1;
+ const int n2 = 2;
+ const int n3 = 4;
+ const int n4 = 6;
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(AssertSumIsEven4, n1, n2, n3, n4);
+ }, "evaluates to 13, which is not even.");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(), 1, 2, 4, 6, 8)
+ << "This failure is expected.";
+ }, "This failure is expected.");
+}
+
+// Tests that predicate assertions evaluates their arguments
+// exactly once.
+TEST(PredTest, SingleEvaluationOnFailure) {
+ // A success case.
+ int n1 = 0;
+ int n2 = 0;
+ EXPECT_PRED2(SumIsEven2, n1++, n2++);
+ EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once.";
+ EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once.";
+
+ // Another success case.
+ n1 = n2 = 0;
+ int n3 = 0;
+ int n4 = 0;
+ int n5 = 0;
+ ASSERT_PRED_FORMAT5(AssertSumIsEven5Functor(),
+ n1++, n2++, n3++, n4++, n5++)
+ << "This failure is UNEXPECTED!";
+ EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once.";
+ EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once.";
+ EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once.";
+ EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once.";
+ EXPECT_EQ(1, n5) << "Argument 5 is not evaluated exactly once.";
+
+ // A failure case.
+ n1 = n2 = n3 = 0;
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED3(SumIsEven3Functor(), ++n1, n2++, n3++)
+ << "This failure is expected.";
+ }, "This failure is expected.");
+ EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once.";
+ EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once.";
+ EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once.";
+
+ // Another failure case.
+ n1 = n2 = n3 = n4 = 0;
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT4(AssertSumIsEven4, ++n1, n2++, n3++, n4++);
+ }, "evaluates to 1, which is not even.");
+ EXPECT_EQ(1, n1) << "Argument 1 is not evaluated exactly once.";
+ EXPECT_EQ(1, n2) << "Argument 2 is not evaluated exactly once.";
+ EXPECT_EQ(1, n3) << "Argument 3 is not evaluated exactly once.";
+ EXPECT_EQ(1, n4) << "Argument 4 is not evaluated exactly once.";
+}
+
+
+// Some helper functions for testing using overloaded/template
+// functions with ASSERT_PREDn and EXPECT_PREDn.
+
+bool IsPositive(double x) {
+ return x > 0;
+}
+
+template <typename T>
+bool IsNegative(T x) {
+ return x < 0;
+}
+
+template <typename T1, typename T2>
+bool GreaterThan(T1 x1, T2 x2) {
+ return x1 > x2;
+}
+
+// Tests that overloaded functions can be used in *_PRED* as long as
+// their types are explicitly specified.
+TEST(PredicateAssertionTest, AcceptsOverloadedFunction) {
+ // C++Builder requires C-style casts rather than static_cast.
+ EXPECT_PRED1((bool (*)(int))(IsPositive), 5); // NOLINT
+ ASSERT_PRED1((bool (*)(double))(IsPositive), 6.0); // NOLINT
+}
+
+// Tests that template functions can be used in *_PRED* as long as
+// their types are explicitly specified.
+TEST(PredicateAssertionTest, AcceptsTemplateFunction) {
+ EXPECT_PRED1(IsNegative<int>, -5);
+ // Makes sure that we can handle templates with more than one
+ // parameter.
+ ASSERT_PRED2((GreaterThan<int, int>), 5, 0);
+}
+
+
+// Some helper functions for testing using overloaded/template
+// functions with ASSERT_PRED_FORMATn and EXPECT_PRED_FORMATn.
+
+AssertionResult IsPositiveFormat(const char* /* expr */, int n) {
+ return n > 0 ? AssertionSuccess() :
+ AssertionFailure(Message() << "Failure");
+}
+
+AssertionResult IsPositiveFormat(const char* /* expr */, double x) {
+ return x > 0 ? AssertionSuccess() :
+ AssertionFailure(Message() << "Failure");
+}
+
+template <typename T>
+AssertionResult IsNegativeFormat(const char* /* expr */, T x) {
+ return x < 0 ? AssertionSuccess() :
+ AssertionFailure(Message() << "Failure");
+}
+
+template <typename T1, typename T2>
+AssertionResult EqualsFormat(const char* /* expr1 */, const char* /* expr2 */,
+ const T1& x1, const T2& x2) {
+ return x1 == x2 ? AssertionSuccess() :
+ AssertionFailure(Message() << "Failure");
+}
+
+// Tests that overloaded functions can be used in *_PRED_FORMAT*
+// without explicitly specifying their types.
+TEST(PredicateFormatAssertionTest, AcceptsOverloadedFunction) {
+ EXPECT_PRED_FORMAT1(IsPositiveFormat, 5);
+ ASSERT_PRED_FORMAT1(IsPositiveFormat, 6.0);
+}
+
+// Tests that template functions can be used in *_PRED_FORMAT* without
+// explicitly specifying their types.
+TEST(PredicateFormatAssertionTest, AcceptsTemplateFunction) {
+ EXPECT_PRED_FORMAT1(IsNegativeFormat, -5);
+ ASSERT_PRED_FORMAT2(EqualsFormat, 3, 3);
+}
+
+
+// Tests string assertions.
+
+// Tests ASSERT_STREQ with non-NULL arguments.
+TEST(StringAssertionTest, ASSERT_STREQ) {
+ const char * const p1 = "good";
+ ASSERT_STREQ(p1, p1);
+
+ // Let p2 have the same content as p1, but be at a different address.
+ const char p2[] = "good";
+ ASSERT_STREQ(p1, p2);
+
+ EXPECT_FATAL_FAILURE(ASSERT_STREQ("bad", "good"),
+ "Expected: \"bad\"");
+}
+
+// Tests ASSERT_STREQ with NULL arguments.
+TEST(StringAssertionTest, ASSERT_STREQ_Null) {
+ ASSERT_STREQ(static_cast<const char *>(NULL), NULL);
+ EXPECT_FATAL_FAILURE(ASSERT_STREQ(NULL, "non-null"),
+ "non-null");
+}
+
+// Tests ASSERT_STREQ with NULL arguments.
+TEST(StringAssertionTest, ASSERT_STREQ_Null2) {
+ EXPECT_FATAL_FAILURE(ASSERT_STREQ("non-null", NULL),
+ "non-null");
+}
+
+// Tests ASSERT_STRNE.
+TEST(StringAssertionTest, ASSERT_STRNE) {
+ ASSERT_STRNE("hi", "Hi");
+ ASSERT_STRNE("Hi", NULL);
+ ASSERT_STRNE(NULL, "Hi");
+ ASSERT_STRNE("", NULL);
+ ASSERT_STRNE(NULL, "");
+ ASSERT_STRNE("", "Hi");
+ ASSERT_STRNE("Hi", "");
+ EXPECT_FATAL_FAILURE(ASSERT_STRNE("Hi", "Hi"),
+ "\"Hi\" vs \"Hi\"");
+}
+
+// Tests ASSERT_STRCASEEQ.
+TEST(StringAssertionTest, ASSERT_STRCASEEQ) {
+ ASSERT_STRCASEEQ("hi", "Hi");
+ ASSERT_STRCASEEQ(static_cast<const char *>(NULL), NULL);
+
+ ASSERT_STRCASEEQ("", "");
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("Hi", "hi2"),
+ "(ignoring case)");
+}
+
+// Tests ASSERT_STRCASENE.
+TEST(StringAssertionTest, ASSERT_STRCASENE) {
+ ASSERT_STRCASENE("hi1", "Hi2");
+ ASSERT_STRCASENE("Hi", NULL);
+ ASSERT_STRCASENE(NULL, "Hi");
+ ASSERT_STRCASENE("", NULL);
+ ASSERT_STRCASENE(NULL, "");
+ ASSERT_STRCASENE("", "Hi");
+ ASSERT_STRCASENE("Hi", "");
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("Hi", "hi"),
+ "(ignoring case)");
+}
+
+// Tests *_STREQ on wide strings.
+TEST(StringAssertionTest, STREQ_Wide) {
+ // NULL strings.
+ ASSERT_STREQ(static_cast<const wchar_t *>(NULL), NULL);
+
+ // Empty strings.
+ ASSERT_STREQ(L"", L"");
+
+ // Non-null vs NULL.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"non-null", NULL),
+ "non-null");
+
+ // Equal strings.
+ EXPECT_STREQ(L"Hi", L"Hi");
+
+ // Unequal strings.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc", L"Abc"),
+ "Abc");
+
+ // Strings containing wide characters.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STREQ(L"abc\x8119", L"abc\x8120"),
+ "abc");
+}
+
+// Tests *_STRNE on wide strings.
+TEST(StringAssertionTest, STRNE_Wide) {
+ // NULL strings.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_STRNE(static_cast<const wchar_t *>(NULL), NULL);
+ }, "");
+
+ // Empty strings.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"", L""),
+ "L\"\"");
+
+ // Non-null vs NULL.
+ ASSERT_STRNE(L"non-null", NULL);
+
+ // Equal strings.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"Hi", L"Hi"),
+ "L\"Hi\"");
+
+ // Unequal strings.
+ EXPECT_STRNE(L"abc", L"Abc");
+
+ // Strings containing wide characters.
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE(L"abc\x8119", L"abc\x8119"),
+ "abc");
+}
+
+// Tests for ::testing::IsSubstring().
+
+// Tests that IsSubstring() returns the correct result when the input
+// argument type is const char*.
+TEST(IsSubstringTest, ReturnsCorrectResultForCString) {
+ EXPECT_FALSE(IsSubstring("", "", NULL, "a"));
+ EXPECT_FALSE(IsSubstring("", "", "b", NULL));
+ EXPECT_FALSE(IsSubstring("", "", "needle", "haystack"));
+
+ EXPECT_TRUE(IsSubstring("", "", static_cast<const char*>(NULL), NULL));
+ EXPECT_TRUE(IsSubstring("", "", "needle", "two needles"));
+}
+
+// Tests that IsSubstring() returns the correct result when the input
+// argument type is const wchar_t*.
+TEST(IsSubstringTest, ReturnsCorrectResultForWideCString) {
+ EXPECT_FALSE(IsSubstring("", "", kNull, L"a"));
+ EXPECT_FALSE(IsSubstring("", "", L"b", kNull));
+ EXPECT_FALSE(IsSubstring("", "", L"needle", L"haystack"));
+
+ EXPECT_TRUE(IsSubstring("", "", static_cast<const wchar_t*>(NULL), NULL));
+ EXPECT_TRUE(IsSubstring("", "", L"needle", L"two needles"));
+}
+
+// Tests that IsSubstring() generates the correct message when the input
+// argument type is const char*.
+TEST(IsSubstringTest, GeneratesCorrectMessageForCString) {
+ EXPECT_STREQ("Value of: needle_expr\n"
+ " Actual: \"needle\"\n"
+ "Expected: a substring of haystack_expr\n"
+ "Which is: \"haystack\"",
+ IsSubstring("needle_expr", "haystack_expr",
+ "needle", "haystack").failure_message());
+}
+
+// Tests that IsSubstring returns the correct result when the input
+// argument type is ::std::string.
+TEST(IsSubstringTest, ReturnsCorrectResultsForStdString) {
+ EXPECT_TRUE(IsSubstring("", "", std::string("hello"), "ahellob"));
+ EXPECT_FALSE(IsSubstring("", "", "hello", std::string("world")));
+}
+
+#if GTEST_HAS_STD_WSTRING
+// Tests that IsSubstring returns the correct result when the input
+// argument type is ::std::wstring.
+TEST(IsSubstringTest, ReturnsCorrectResultForStdWstring) {
+ EXPECT_TRUE(IsSubstring("", "", ::std::wstring(L"needle"), L"two needles"));
+ EXPECT_FALSE(IsSubstring("", "", L"needle", ::std::wstring(L"haystack")));
+}
+
+// Tests that IsSubstring() generates the correct message when the input
+// argument type is ::std::wstring.
+TEST(IsSubstringTest, GeneratesCorrectMessageForWstring) {
+ EXPECT_STREQ("Value of: needle_expr\n"
+ " Actual: L\"needle\"\n"
+ "Expected: a substring of haystack_expr\n"
+ "Which is: L\"haystack\"",
+ IsSubstring(
+ "needle_expr", "haystack_expr",
+ ::std::wstring(L"needle"), L"haystack").failure_message());
+}
+
+#endif // GTEST_HAS_STD_WSTRING
+
+// Tests for ::testing::IsNotSubstring().
+
+// Tests that IsNotSubstring() returns the correct result when the input
+// argument type is const char*.
+TEST(IsNotSubstringTest, ReturnsCorrectResultForCString) {
+ EXPECT_TRUE(IsNotSubstring("", "", "needle", "haystack"));
+ EXPECT_FALSE(IsNotSubstring("", "", "needle", "two needles"));
+}
+
+// Tests that IsNotSubstring() returns the correct result when the input
+// argument type is const wchar_t*.
+TEST(IsNotSubstringTest, ReturnsCorrectResultForWideCString) {
+ EXPECT_TRUE(IsNotSubstring("", "", L"needle", L"haystack"));
+ EXPECT_FALSE(IsNotSubstring("", "", L"needle", L"two needles"));
+}
+
+// Tests that IsNotSubstring() generates the correct message when the input
+// argument type is const wchar_t*.
+TEST(IsNotSubstringTest, GeneratesCorrectMessageForWideCString) {
+ EXPECT_STREQ("Value of: needle_expr\n"
+ " Actual: L\"needle\"\n"
+ "Expected: not a substring of haystack_expr\n"
+ "Which is: L\"two needles\"",
+ IsNotSubstring(
+ "needle_expr", "haystack_expr",
+ L"needle", L"two needles").failure_message());
+}
+
+// Tests that IsNotSubstring returns the correct result when the input
+// argument type is ::std::string.
+TEST(IsNotSubstringTest, ReturnsCorrectResultsForStdString) {
+ EXPECT_FALSE(IsNotSubstring("", "", std::string("hello"), "ahellob"));
+ EXPECT_TRUE(IsNotSubstring("", "", "hello", std::string("world")));
+}
+
+// Tests that IsNotSubstring() generates the correct message when the input
+// argument type is ::std::string.
+TEST(IsNotSubstringTest, GeneratesCorrectMessageForStdString) {
+ EXPECT_STREQ("Value of: needle_expr\n"
+ " Actual: \"needle\"\n"
+ "Expected: not a substring of haystack_expr\n"
+ "Which is: \"two needles\"",
+ IsNotSubstring(
+ "needle_expr", "haystack_expr",
+ ::std::string("needle"), "two needles").failure_message());
+}
+
+#if GTEST_HAS_STD_WSTRING
+
+// Tests that IsNotSubstring returns the correct result when the input
+// argument type is ::std::wstring.
+TEST(IsNotSubstringTest, ReturnsCorrectResultForStdWstring) {
+ EXPECT_FALSE(
+ IsNotSubstring("", "", ::std::wstring(L"needle"), L"two needles"));
+ EXPECT_TRUE(IsNotSubstring("", "", L"needle", ::std::wstring(L"haystack")));
+}
+
+#endif // GTEST_HAS_STD_WSTRING
+
+// Tests floating-point assertions.
+
+template <typename RawType>
+class FloatingPointTest : public Test {
+ protected:
+
+ // Pre-calculated numbers to be used by the tests.
+ struct TestValues {
+ RawType close_to_positive_zero;
+ RawType close_to_negative_zero;
+ RawType further_from_negative_zero;
+
+ RawType close_to_one;
+ RawType further_from_one;
+
+ RawType infinity;
+ RawType close_to_infinity;
+ RawType further_from_infinity;
+
+ RawType nan1;
+ RawType nan2;
+ };
+
+ typedef typename testing::internal::FloatingPoint<RawType> Floating;
+ typedef typename Floating::Bits Bits;
+
+ virtual void SetUp() {
+ const size_t max_ulps = Floating::kMaxUlps;
+
+ // The bits that represent 0.0.
+ const Bits zero_bits = Floating(0).bits();
+
+ // Makes some numbers close to 0.0.
+ values_.close_to_positive_zero = Floating::ReinterpretBits(
+ zero_bits + max_ulps/2);
+ values_.close_to_negative_zero = -Floating::ReinterpretBits(
+ zero_bits + max_ulps - max_ulps/2);
+ values_.further_from_negative_zero = -Floating::ReinterpretBits(
+ zero_bits + max_ulps + 1 - max_ulps/2);
+
+ // The bits that represent 1.0.
+ const Bits one_bits = Floating(1).bits();
+
+ // Makes some numbers close to 1.0.
+ values_.close_to_one = Floating::ReinterpretBits(one_bits + max_ulps);
+ values_.further_from_one = Floating::ReinterpretBits(
+ one_bits + max_ulps + 1);
+
+ // +infinity.
+ values_.infinity = Floating::Infinity();
+
+ // The bits that represent +infinity.
+ const Bits infinity_bits = Floating(values_.infinity).bits();
+
+ // Makes some numbers close to infinity.
+ values_.close_to_infinity = Floating::ReinterpretBits(
+ infinity_bits - max_ulps);
+ values_.further_from_infinity = Floating::ReinterpretBits(
+ infinity_bits - max_ulps - 1);
+
+ // Makes some NAN's. Sets the most significant bit of the fraction so that
+ // our NaN's are quiet; trying to process a signaling NaN would raise an
+ // exception if our environment enables floating point exceptions.
+ values_.nan1 = Floating::ReinterpretBits(Floating::kExponentBitMask
+ | (static_cast<Bits>(1) << (Floating::kFractionBitCount - 1)) | 1);
+ values_.nan2 = Floating::ReinterpretBits(Floating::kExponentBitMask
+ | (static_cast<Bits>(1) << (Floating::kFractionBitCount - 1)) | 200);
+ }
+
+ void TestSize() {
+ EXPECT_EQ(sizeof(RawType), sizeof(Bits));
+ }
+
+ static TestValues values_;
+};
+
+template <typename RawType>
+typename FloatingPointTest<RawType>::TestValues
+ FloatingPointTest<RawType>::values_;
+
+// Instantiates FloatingPointTest for testing *_FLOAT_EQ.
+typedef FloatingPointTest<float> FloatTest;
+
+// Tests that the size of Float::Bits matches the size of float.
+TEST_F(FloatTest, Size) {
+ TestSize();
+}
+
+// Tests comparing with +0 and -0.
+TEST_F(FloatTest, Zeros) {
+ EXPECT_FLOAT_EQ(0.0, -0.0);
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(-0.0, 1.0),
+ "1.0");
+ EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.5),
+ "1.5");
+}
+
+// Tests comparing numbers close to 0.
+//
+// This ensures that *_FLOAT_EQ handles the sign correctly and no
+// overflow occurs when comparing numbers whose absolute value is very
+// small.
+TEST_F(FloatTest, AlmostZeros) {
+ // In C++Builder, names within local classes (such as used by
+ // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the
+ // scoping class. Use a static local alias as a workaround.
+ // We use the assignment syntax since some compilers, like Sun Studio,
+ // don't allow initializing references using construction syntax
+ // (parentheses).
+ static const FloatTest::TestValues& v = this->values_;
+
+ EXPECT_FLOAT_EQ(0.0, v.close_to_positive_zero);
+ EXPECT_FLOAT_EQ(-0.0, v.close_to_negative_zero);
+ EXPECT_FLOAT_EQ(v.close_to_positive_zero, v.close_to_negative_zero);
+
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_FLOAT_EQ(v.close_to_positive_zero,
+ v.further_from_negative_zero);
+ }, "v.further_from_negative_zero");
+}
+
+// Tests comparing numbers close to each other.
+TEST_F(FloatTest, SmallDiff) {
+ EXPECT_FLOAT_EQ(1.0, values_.close_to_one);
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, values_.further_from_one),
+ "values_.further_from_one");
+}
+
+// Tests comparing numbers far apart.
+TEST_F(FloatTest, LargeDiff) {
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(2.5, 3.0),
+ "3.0");
+}
+
+// Tests comparing with infinity.
+//
+// This ensures that no overflow occurs when comparing numbers whose
+// absolute value is very large.
+TEST_F(FloatTest, Infinity) {
+ EXPECT_FLOAT_EQ(values_.infinity, values_.close_to_infinity);
+ EXPECT_FLOAT_EQ(-values_.infinity, -values_.close_to_infinity);
+#if !GTEST_OS_SYMBIAN
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, -values_.infinity),
+ "-values_.infinity");
+
+ // This is interesting as the representations of infinity and nan1
+ // are only 1 DLP apart.
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.infinity, values_.nan1),
+ "values_.nan1");
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that comparing with NAN always returns false.
+TEST_F(FloatTest, NaN) {
+#if !GTEST_OS_SYMBIAN
+// Nokia's STLport crashes if we try to output infinity or NaN.
+
+ // In C++Builder, names within local classes (such as used by
+ // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the
+ // scoping class. Use a static local alias as a workaround.
+ // We use the assignment syntax since some compilers, like Sun Studio,
+ // don't allow initializing references using construction syntax
+ // (parentheses).
+ static const FloatTest::TestValues& v = this->values_;
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan1),
+ "v.nan1");
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(v.nan1, v.nan2),
+ "v.nan2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(1.0, v.nan1),
+ "v.nan1");
+
+ EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(v.nan1, v.infinity),
+ "v.infinity");
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that *_FLOAT_EQ are reflexive.
+TEST_F(FloatTest, Reflexive) {
+ EXPECT_FLOAT_EQ(0.0, 0.0);
+ EXPECT_FLOAT_EQ(1.0, 1.0);
+ ASSERT_FLOAT_EQ(values_.infinity, values_.infinity);
+}
+
+// Tests that *_FLOAT_EQ are commutative.
+TEST_F(FloatTest, Commutative) {
+ // We already tested EXPECT_FLOAT_EQ(1.0, values_.close_to_one).
+ EXPECT_FLOAT_EQ(values_.close_to_one, 1.0);
+
+ // We already tested EXPECT_FLOAT_EQ(1.0, values_.further_from_one).
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(values_.further_from_one, 1.0),
+ "1.0");
+}
+
+// Tests EXPECT_NEAR.
+TEST_F(FloatTest, EXPECT_NEAR) {
+ EXPECT_NEAR(-1.0f, -1.1f, 0.2f);
+ EXPECT_NEAR(2.0f, 3.0f, 1.0f);
+ EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0f,1.5f, 0.25f), // NOLINT
+ "The difference between 1.0f and 1.5f is 0.5, "
+ "which exceeds 0.25f");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous line.
+}
+
+// Tests ASSERT_NEAR.
+TEST_F(FloatTest, ASSERT_NEAR) {
+ ASSERT_NEAR(-1.0f, -1.1f, 0.2f);
+ ASSERT_NEAR(2.0f, 3.0f, 1.0f);
+ EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0f,1.5f, 0.25f), // NOLINT
+ "The difference between 1.0f and 1.5f is 0.5, "
+ "which exceeds 0.25f");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous line.
+}
+
+// Tests the cases where FloatLE() should succeed.
+TEST_F(FloatTest, FloatLESucceeds) {
+ EXPECT_PRED_FORMAT2(FloatLE, 1.0f, 2.0f); // When val1 < val2,
+ ASSERT_PRED_FORMAT2(FloatLE, 1.0f, 1.0f); // val1 == val2,
+
+ // or when val1 is greater than, but almost equals to, val2.
+ EXPECT_PRED_FORMAT2(FloatLE, values_.close_to_positive_zero, 0.0f);
+}
+
+// Tests the cases where FloatLE() should fail.
+TEST_F(FloatTest, FloatLEFails) {
+ // When val1 is greater than val2 by a large margin,
+ EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(FloatLE, 2.0f, 1.0f),
+ "(2.0f) <= (1.0f)");
+
+ // or by a small yet non-negligible margin,
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(FloatLE, values_.further_from_one, 1.0f);
+ }, "(values_.further_from_one) <= (1.0f)");
+
+#if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__)
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ // C++Builder gives bad results for ordered comparisons involving NaNs
+ // due to compiler bugs.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(FloatLE, values_.nan1, values_.infinity);
+ }, "(values_.nan1) <= (values_.infinity)");
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(FloatLE, -values_.infinity, values_.nan1);
+ }, "(-values_.infinity) <= (values_.nan1)");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(FloatLE, values_.nan1, values_.nan1);
+ }, "(values_.nan1) <= (values_.nan1)");
+#endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__)
+}
+
+// Instantiates FloatingPointTest for testing *_DOUBLE_EQ.
+typedef FloatingPointTest<double> DoubleTest;
+
+// Tests that the size of Double::Bits matches the size of double.
+TEST_F(DoubleTest, Size) {
+ TestSize();
+}
+
+// Tests comparing with +0 and -0.
+TEST_F(DoubleTest, Zeros) {
+ EXPECT_DOUBLE_EQ(0.0, -0.0);
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(-0.0, 1.0),
+ "1.0");
+ EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(0.0, 1.0),
+ "1.0");
+}
+
+// Tests comparing numbers close to 0.
+//
+// This ensures that *_DOUBLE_EQ handles the sign correctly and no
+// overflow occurs when comparing numbers whose absolute value is very
+// small.
+TEST_F(DoubleTest, AlmostZeros) {
+ // In C++Builder, names within local classes (such as used by
+ // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the
+ // scoping class. Use a static local alias as a workaround.
+ // We use the assignment syntax since some compilers, like Sun Studio,
+ // don't allow initializing references using construction syntax
+ // (parentheses).
+ static const DoubleTest::TestValues& v = this->values_;
+
+ EXPECT_DOUBLE_EQ(0.0, v.close_to_positive_zero);
+ EXPECT_DOUBLE_EQ(-0.0, v.close_to_negative_zero);
+ EXPECT_DOUBLE_EQ(v.close_to_positive_zero, v.close_to_negative_zero);
+
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_DOUBLE_EQ(v.close_to_positive_zero,
+ v.further_from_negative_zero);
+ }, "v.further_from_negative_zero");
+}
+
+// Tests comparing numbers close to each other.
+TEST_F(DoubleTest, SmallDiff) {
+ EXPECT_DOUBLE_EQ(1.0, values_.close_to_one);
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, values_.further_from_one),
+ "values_.further_from_one");
+}
+
+// Tests comparing numbers far apart.
+TEST_F(DoubleTest, LargeDiff) {
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(2.0, 3.0),
+ "3.0");
+}
+
+// Tests comparing with infinity.
+//
+// This ensures that no overflow occurs when comparing numbers whose
+// absolute value is very large.
+TEST_F(DoubleTest, Infinity) {
+ EXPECT_DOUBLE_EQ(values_.infinity, values_.close_to_infinity);
+ EXPECT_DOUBLE_EQ(-values_.infinity, -values_.close_to_infinity);
+#if !GTEST_OS_SYMBIAN
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, -values_.infinity),
+ "-values_.infinity");
+
+ // This is interesting as the representations of infinity_ and nan1_
+ // are only 1 DLP apart.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.infinity, values_.nan1),
+ "values_.nan1");
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that comparing with NAN always returns false.
+TEST_F(DoubleTest, NaN) {
+#if !GTEST_OS_SYMBIAN
+ // In C++Builder, names within local classes (such as used by
+ // EXPECT_FATAL_FAILURE) cannot be resolved against static members of the
+ // scoping class. Use a static local alias as a workaround.
+ // We use the assignment syntax since some compilers, like Sun Studio,
+ // don't allow initializing references using construction syntax
+ // (parentheses).
+ static const DoubleTest::TestValues& v = this->values_;
+
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan1),
+ "v.nan1");
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(v.nan1, v.nan2), "v.nan2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1.0, v.nan1), "v.nan1");
+ EXPECT_FATAL_FAILURE(ASSERT_DOUBLE_EQ(v.nan1, v.infinity),
+ "v.infinity");
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that *_DOUBLE_EQ are reflexive.
+TEST_F(DoubleTest, Reflexive) {
+ EXPECT_DOUBLE_EQ(0.0, 0.0);
+ EXPECT_DOUBLE_EQ(1.0, 1.0);
+#if !GTEST_OS_SYMBIAN
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ ASSERT_DOUBLE_EQ(values_.infinity, values_.infinity);
+#endif // !GTEST_OS_SYMBIAN
+}
+
+// Tests that *_DOUBLE_EQ are commutative.
+TEST_F(DoubleTest, Commutative) {
+ // We already tested EXPECT_DOUBLE_EQ(1.0, values_.close_to_one).
+ EXPECT_DOUBLE_EQ(values_.close_to_one, 1.0);
+
+ // We already tested EXPECT_DOUBLE_EQ(1.0, values_.further_from_one).
+ EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(values_.further_from_one, 1.0),
+ "1.0");
+}
+
+// Tests EXPECT_NEAR.
+TEST_F(DoubleTest, EXPECT_NEAR) {
+ EXPECT_NEAR(-1.0, -1.1, 0.2);
+ EXPECT_NEAR(2.0, 3.0, 1.0);
+ EXPECT_NONFATAL_FAILURE(EXPECT_NEAR(1.0, 1.5, 0.25), // NOLINT
+ "The difference between 1.0 and 1.5 is 0.5, "
+ "which exceeds 0.25");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous statement.
+}
+
+// Tests ASSERT_NEAR.
+TEST_F(DoubleTest, ASSERT_NEAR) {
+ ASSERT_NEAR(-1.0, -1.1, 0.2);
+ ASSERT_NEAR(2.0, 3.0, 1.0);
+ EXPECT_FATAL_FAILURE(ASSERT_NEAR(1.0, 1.5, 0.25), // NOLINT
+ "The difference between 1.0 and 1.5 is 0.5, "
+ "which exceeds 0.25");
+ // To work around a bug in gcc 2.95.0, there is intentionally no
+ // space after the first comma in the previous statement.
+}
+
+// Tests the cases where DoubleLE() should succeed.
+TEST_F(DoubleTest, DoubleLESucceeds) {
+ EXPECT_PRED_FORMAT2(DoubleLE, 1.0, 2.0); // When val1 < val2,
+ ASSERT_PRED_FORMAT2(DoubleLE, 1.0, 1.0); // val1 == val2,
+
+ // or when val1 is greater than, but almost equals to, val2.
+ EXPECT_PRED_FORMAT2(DoubleLE, values_.close_to_positive_zero, 0.0);
+}
+
+// Tests the cases where DoubleLE() should fail.
+TEST_F(DoubleTest, DoubleLEFails) {
+ // When val1 is greater than val2 by a large margin,
+ EXPECT_NONFATAL_FAILURE(EXPECT_PRED_FORMAT2(DoubleLE, 2.0, 1.0),
+ "(2.0) <= (1.0)");
+
+ // or by a small yet non-negligible margin,
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(DoubleLE, values_.further_from_one, 1.0);
+ }, "(values_.further_from_one) <= (1.0)");
+
+#if !GTEST_OS_SYMBIAN && !defined(__BORLANDC__)
+ // Nokia's STLport crashes if we try to output infinity or NaN.
+ // C++Builder gives bad results for ordered comparisons involving NaNs
+ // due to compiler bugs.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.infinity);
+ }, "(values_.nan1) <= (values_.infinity)");
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_PRED_FORMAT2(DoubleLE, -values_.infinity, values_.nan1);
+ }, " (-values_.infinity) <= (values_.nan1)");
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_PRED_FORMAT2(DoubleLE, values_.nan1, values_.nan1);
+ }, "(values_.nan1) <= (values_.nan1)");
+#endif // !GTEST_OS_SYMBIAN && !defined(__BORLANDC__)
+}
+
+
+// Verifies that a test or test case whose name starts with DISABLED_ is
+// not run.
+
+// A test whose name starts with DISABLED_.
+// Should not run.
+TEST(DisabledTest, DISABLED_TestShouldNotRun) {
+ FAIL() << "Unexpected failure: Disabled test should not be run.";
+}
+
+// A test whose name does not start with DISABLED_.
+// Should run.
+TEST(DisabledTest, NotDISABLED_TestShouldRun) {
+ EXPECT_EQ(1, 1);
+}
+
+// A test case whose name starts with DISABLED_.
+// Should not run.
+TEST(DISABLED_TestCase, TestShouldNotRun) {
+ FAIL() << "Unexpected failure: Test in disabled test case should not be run.";
+}
+
+// A test case and test whose names start with DISABLED_.
+// Should not run.
+TEST(DISABLED_TestCase, DISABLED_TestShouldNotRun) {
+ FAIL() << "Unexpected failure: Test in disabled test case should not be run.";
+}
+
+// Check that when all tests in a test case are disabled, SetupTestCase() and
+// TearDownTestCase() are not called.
+class DisabledTestsTest : public Test {
+ protected:
+ static void SetUpTestCase() {
+ FAIL() << "Unexpected failure: All tests disabled in test case. "
+ "SetupTestCase() should not be called.";
+ }
+
+ static void TearDownTestCase() {
+ FAIL() << "Unexpected failure: All tests disabled in test case. "
+ "TearDownTestCase() should not be called.";
+ }
+};
+
+TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_1) {
+ FAIL() << "Unexpected failure: Disabled test should not be run.";
+}
+
+TEST_F(DisabledTestsTest, DISABLED_TestShouldNotRun_2) {
+ FAIL() << "Unexpected failure: Disabled test should not be run.";
+}
+
+// Tests that disabled typed tests aren't run.
+
+#if GTEST_HAS_TYPED_TEST
+
+template <typename T>
+class TypedTest : public Test {
+};
+
+typedef testing::Types<int, double> NumericTypes;
+TYPED_TEST_CASE(TypedTest, NumericTypes);
+
+TYPED_TEST(TypedTest, DISABLED_ShouldNotRun) {
+ FAIL() << "Unexpected failure: Disabled typed test should not run.";
+}
+
+template <typename T>
+class DISABLED_TypedTest : public Test {
+};
+
+TYPED_TEST_CASE(DISABLED_TypedTest, NumericTypes);
+
+TYPED_TEST(DISABLED_TypedTest, ShouldNotRun) {
+ FAIL() << "Unexpected failure: Disabled typed test should not run.";
+}
+
+#endif // GTEST_HAS_TYPED_TEST
+
+// Tests that disabled type-parameterized tests aren't run.
+
+#if GTEST_HAS_TYPED_TEST_P
+
+template <typename T>
+class TypedTestP : public Test {
+};
+
+TYPED_TEST_CASE_P(TypedTestP);
+
+TYPED_TEST_P(TypedTestP, DISABLED_ShouldNotRun) {
+ FAIL() << "Unexpected failure: "
+ << "Disabled type-parameterized test should not run.";
+}
+
+REGISTER_TYPED_TEST_CASE_P(TypedTestP, DISABLED_ShouldNotRun);
+
+INSTANTIATE_TYPED_TEST_CASE_P(My, TypedTestP, NumericTypes);
+
+template <typename T>
+class DISABLED_TypedTestP : public Test {
+};
+
+TYPED_TEST_CASE_P(DISABLED_TypedTestP);
+
+TYPED_TEST_P(DISABLED_TypedTestP, ShouldNotRun) {
+ FAIL() << "Unexpected failure: "
+ << "Disabled type-parameterized test should not run.";
+}
+
+REGISTER_TYPED_TEST_CASE_P(DISABLED_TypedTestP, ShouldNotRun);
+
+INSTANTIATE_TYPED_TEST_CASE_P(My, DISABLED_TypedTestP, NumericTypes);
+
+#endif // GTEST_HAS_TYPED_TEST_P
+
+// Tests that assertion macros evaluate their arguments exactly once.
+
+class SingleEvaluationTest : public Test {
+ public: // Must be public and not protected due to a bug in g++ 3.4.2.
+ // This helper function is needed by the FailedASSERT_STREQ test
+ // below. It's public to work around C++Builder's bug with scoping local
+ // classes.
+ static void CompareAndIncrementCharPtrs() {
+ ASSERT_STREQ(p1_++, p2_++);
+ }
+
+ // This helper function is needed by the FailedASSERT_NE test below. It's
+ // public to work around C++Builder's bug with scoping local classes.
+ static void CompareAndIncrementInts() {
+ ASSERT_NE(a_++, b_++);
+ }
+
+ protected:
+ SingleEvaluationTest() {
+ p1_ = s1_;
+ p2_ = s2_;
+ a_ = 0;
+ b_ = 0;
+ }
+
+ static const char* const s1_;
+ static const char* const s2_;
+ static const char* p1_;
+ static const char* p2_;
+
+ static int a_;
+ static int b_;
+};
+
+const char* const SingleEvaluationTest::s1_ = "01234";
+const char* const SingleEvaluationTest::s2_ = "abcde";
+const char* SingleEvaluationTest::p1_;
+const char* SingleEvaluationTest::p2_;
+int SingleEvaluationTest::a_;
+int SingleEvaluationTest::b_;
+
+// Tests that when ASSERT_STREQ fails, it evaluates its arguments
+// exactly once.
+TEST_F(SingleEvaluationTest, FailedASSERT_STREQ) {
+ EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementCharPtrs(),
+ "p2_++");
+ EXPECT_EQ(s1_ + 1, p1_);
+ EXPECT_EQ(s2_ + 1, p2_);
+}
+
+// Tests that string assertion arguments are evaluated exactly once.
+TEST_F(SingleEvaluationTest, ASSERT_STR) {
+ // successful EXPECT_STRNE
+ EXPECT_STRNE(p1_++, p2_++);
+ EXPECT_EQ(s1_ + 1, p1_);
+ EXPECT_EQ(s2_ + 1, p2_);
+
+ // failed EXPECT_STRCASEEQ
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ(p1_++, p2_++),
+ "ignoring case");
+ EXPECT_EQ(s1_ + 2, p1_);
+ EXPECT_EQ(s2_ + 2, p2_);
+}
+
+// Tests that when ASSERT_NE fails, it evaluates its arguments exactly
+// once.
+TEST_F(SingleEvaluationTest, FailedASSERT_NE) {
+ EXPECT_FATAL_FAILURE(SingleEvaluationTest::CompareAndIncrementInts(),
+ "(a_++) != (b_++)");
+ EXPECT_EQ(1, a_);
+ EXPECT_EQ(1, b_);
+}
+
+// Tests that assertion arguments are evaluated exactly once.
+TEST_F(SingleEvaluationTest, OtherCases) {
+ // successful EXPECT_TRUE
+ EXPECT_TRUE(0 == a_++); // NOLINT
+ EXPECT_EQ(1, a_);
+
+ // failed EXPECT_TRUE
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(-1 == a_++), "-1 == a_++");
+ EXPECT_EQ(2, a_);
+
+ // successful EXPECT_GT
+ EXPECT_GT(a_++, b_++);
+ EXPECT_EQ(3, a_);
+ EXPECT_EQ(1, b_);
+
+ // failed EXPECT_LT
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(a_++, b_++), "(a_++) < (b_++)");
+ EXPECT_EQ(4, a_);
+ EXPECT_EQ(2, b_);
+
+ // successful ASSERT_TRUE
+ ASSERT_TRUE(0 < a_++); // NOLINT
+ EXPECT_EQ(5, a_);
+
+ // successful ASSERT_GT
+ ASSERT_GT(a_++, b_++);
+ EXPECT_EQ(6, a_);
+ EXPECT_EQ(3, b_);
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+void ThrowAnInteger() {
+ throw 1;
+}
+
+// Tests that assertion arguments are evaluated exactly once.
+TEST_F(SingleEvaluationTest, ExceptionTests) {
+ // successful EXPECT_THROW
+ EXPECT_THROW({ // NOLINT
+ a_++;
+ ThrowAnInteger();
+ }, int);
+ EXPECT_EQ(1, a_);
+
+ // failed EXPECT_THROW, throws different
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW({ // NOLINT
+ a_++;
+ ThrowAnInteger();
+ }, bool), "throws a different type");
+ EXPECT_EQ(2, a_);
+
+ // failed EXPECT_THROW, throws nothing
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(a_++, bool), "throws nothing");
+ EXPECT_EQ(3, a_);
+
+ // successful EXPECT_NO_THROW
+ EXPECT_NO_THROW(a_++);
+ EXPECT_EQ(4, a_);
+
+ // failed EXPECT_NO_THROW
+ EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW({ // NOLINT
+ a_++;
+ ThrowAnInteger();
+ }), "it throws");
+ EXPECT_EQ(5, a_);
+
+ // successful EXPECT_ANY_THROW
+ EXPECT_ANY_THROW({ // NOLINT
+ a_++;
+ ThrowAnInteger();
+ });
+ EXPECT_EQ(6, a_);
+
+ // failed EXPECT_ANY_THROW
+ EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(a_++), "it doesn't");
+ EXPECT_EQ(7, a_);
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Tests {ASSERT|EXPECT}_NO_FATAL_FAILURE.
+class NoFatalFailureTest : public Test {
+ protected:
+ void Succeeds() {}
+ void FailsNonFatal() {
+ ADD_FAILURE() << "some non-fatal failure";
+ }
+ void Fails() {
+ FAIL() << "some fatal failure";
+ }
+
+ void DoAssertNoFatalFailureOnFails() {
+ ASSERT_NO_FATAL_FAILURE(Fails());
+ ADD_FAILURE() << "shold not reach here.";
+ }
+
+ void DoExpectNoFatalFailureOnFails() {
+ EXPECT_NO_FATAL_FAILURE(Fails());
+ ADD_FAILURE() << "other failure";
+ }
+};
+
+TEST_F(NoFatalFailureTest, NoFailure) {
+ EXPECT_NO_FATAL_FAILURE(Succeeds());
+ ASSERT_NO_FATAL_FAILURE(Succeeds());
+}
+
+TEST_F(NoFatalFailureTest, NonFatalIsNoFailure) {
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_NO_FATAL_FAILURE(FailsNonFatal()),
+ "some non-fatal failure");
+ EXPECT_NONFATAL_FAILURE(
+ ASSERT_NO_FATAL_FAILURE(FailsNonFatal()),
+ "some non-fatal failure");
+}
+
+TEST_F(NoFatalFailureTest, AssertNoFatalFailureOnFatalFailure) {
+ TestPartResultArray gtest_failures;
+ {
+ ScopedFakeTestPartResultReporter gtest_reporter(&gtest_failures);
+ DoAssertNoFatalFailureOnFails();
+ }
+ ASSERT_EQ(2, gtest_failures.size());
+ EXPECT_EQ(TestPartResult::kFatalFailure,
+ gtest_failures.GetTestPartResult(0).type());
+ EXPECT_EQ(TestPartResult::kFatalFailure,
+ gtest_failures.GetTestPartResult(1).type());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure",
+ gtest_failures.GetTestPartResult(0).message());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does",
+ gtest_failures.GetTestPartResult(1).message());
+}
+
+TEST_F(NoFatalFailureTest, ExpectNoFatalFailureOnFatalFailure) {
+ TestPartResultArray gtest_failures;
+ {
+ ScopedFakeTestPartResultReporter gtest_reporter(&gtest_failures);
+ DoExpectNoFatalFailureOnFails();
+ }
+ ASSERT_EQ(3, gtest_failures.size());
+ EXPECT_EQ(TestPartResult::kFatalFailure,
+ gtest_failures.GetTestPartResult(0).type());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure,
+ gtest_failures.GetTestPartResult(1).type());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure,
+ gtest_failures.GetTestPartResult(2).type());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "some fatal failure",
+ gtest_failures.GetTestPartResult(0).message());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "it does",
+ gtest_failures.GetTestPartResult(1).message());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "other failure",
+ gtest_failures.GetTestPartResult(2).message());
+}
+
+TEST_F(NoFatalFailureTest, MessageIsStreamable) {
+ TestPartResultArray gtest_failures;
+ {
+ ScopedFakeTestPartResultReporter gtest_reporter(&gtest_failures);
+ EXPECT_NO_FATAL_FAILURE(FAIL() << "foo") << "my message";
+ }
+ ASSERT_EQ(2, gtest_failures.size());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure,
+ gtest_failures.GetTestPartResult(0).type());
+ EXPECT_EQ(TestPartResult::kNonFatalFailure,
+ gtest_failures.GetTestPartResult(1).type());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "foo",
+ gtest_failures.GetTestPartResult(0).message());
+ EXPECT_PRED_FORMAT2(testing::IsSubstring, "my message",
+ gtest_failures.GetTestPartResult(1).message());
+}
+
+// Tests non-string assertions.
+
+// Tests EqFailure(), used for implementing *EQ* assertions.
+TEST(AssertionTest, EqFailure) {
+ const String foo_val("5"), bar_val("6");
+ const String msg1(
+ EqFailure("foo", "bar", foo_val, bar_val, false)
+ .failure_message());
+ EXPECT_STREQ(
+ "Value of: bar\n"
+ " Actual: 6\n"
+ "Expected: foo\n"
+ "Which is: 5",
+ msg1.c_str());
+
+ const String msg2(
+ EqFailure("foo", "6", foo_val, bar_val, false)
+ .failure_message());
+ EXPECT_STREQ(
+ "Value of: 6\n"
+ "Expected: foo\n"
+ "Which is: 5",
+ msg2.c_str());
+
+ const String msg3(
+ EqFailure("5", "bar", foo_val, bar_val, false)
+ .failure_message());
+ EXPECT_STREQ(
+ "Value of: bar\n"
+ " Actual: 6\n"
+ "Expected: 5",
+ msg3.c_str());
+
+ const String msg4(
+ EqFailure("5", "6", foo_val, bar_val, false).failure_message());
+ EXPECT_STREQ(
+ "Value of: 6\n"
+ "Expected: 5",
+ msg4.c_str());
+
+ const String msg5(
+ EqFailure("foo", "bar",
+ String("\"x\""), String("\"y\""),
+ true).failure_message());
+ EXPECT_STREQ(
+ "Value of: bar\n"
+ " Actual: \"y\"\n"
+ "Expected: foo (ignoring case)\n"
+ "Which is: \"x\"",
+ msg5.c_str());
+}
+
+// Tests AppendUserMessage(), used for implementing the *EQ* macros.
+TEST(AssertionTest, AppendUserMessage) {
+ const String foo("foo");
+
+ Message msg;
+ EXPECT_STREQ("foo",
+ AppendUserMessage(foo, msg).c_str());
+
+ msg << "bar";
+ EXPECT_STREQ("foo\nbar",
+ AppendUserMessage(foo, msg).c_str());
+}
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true", "Unreachable code"
+#pragma option push -w-ccc -w-rch
+#endif
+
+// Tests ASSERT_TRUE.
+TEST(AssertionTest, ASSERT_TRUE) {
+ ASSERT_TRUE(2 > 1); // NOLINT
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(2 < 1),
+ "2 < 1");
+}
+
+// Tests ASSERT_TRUE(predicate) for predicates returning AssertionResult.
+TEST(AssertionTest, AssertTrueWithAssertionResult) {
+ ASSERT_TRUE(ResultIsEven(2));
+#if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600
+ // ICE's in C++Builder 2007.
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEven(3)),
+ "Value of: ResultIsEven(3)\n"
+ " Actual: false (3 is odd)\n"
+ "Expected: true");
+#endif
+ ASSERT_TRUE(ResultIsEvenNoExplanation(2));
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(ResultIsEvenNoExplanation(3)),
+ "Value of: ResultIsEvenNoExplanation(3)\n"
+ " Actual: false (3 is odd)\n"
+ "Expected: true");
+}
+
+// Tests ASSERT_FALSE.
+TEST(AssertionTest, ASSERT_FALSE) {
+ ASSERT_FALSE(2 < 1); // NOLINT
+ EXPECT_FATAL_FAILURE(ASSERT_FALSE(2 > 1),
+ "Value of: 2 > 1\n"
+ " Actual: true\n"
+ "Expected: false");
+}
+
+// Tests ASSERT_FALSE(predicate) for predicates returning AssertionResult.
+TEST(AssertionTest, AssertFalseWithAssertionResult) {
+ ASSERT_FALSE(ResultIsEven(3));
+#if !defined(__BORLANDC__) || __BORLANDC__ >= 0x600
+ // ICE's in C++Builder 2007.
+ EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEven(2)),
+ "Value of: ResultIsEven(2)\n"
+ " Actual: true (2 is even)\n"
+ "Expected: false");
+#endif
+ ASSERT_FALSE(ResultIsEvenNoExplanation(3));
+ EXPECT_FATAL_FAILURE(ASSERT_FALSE(ResultIsEvenNoExplanation(2)),
+ "Value of: ResultIsEvenNoExplanation(2)\n"
+ " Actual: true\n"
+ "Expected: false");
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" supressed them
+#pragma option pop
+#endif
+
+// Tests using ASSERT_EQ on double values. The purpose is to make
+// sure that the specialization we did for integer and anonymous enums
+// isn't used for double arguments.
+TEST(ExpectTest, ASSERT_EQ_Double) {
+ // A success.
+ ASSERT_EQ(5.6, 5.6);
+
+ // A failure.
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(5.1, 5.2),
+ "5.1");
+}
+
+// Tests ASSERT_EQ.
+TEST(AssertionTest, ASSERT_EQ) {
+ ASSERT_EQ(5, 2 + 3);
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(5, 2*3),
+ "Value of: 2*3\n"
+ " Actual: 6\n"
+ "Expected: 5");
+}
+
+// Tests ASSERT_EQ(NULL, pointer).
+#if GTEST_CAN_COMPARE_NULL
+TEST(AssertionTest, ASSERT_EQ_NULL) {
+ // A success.
+ const char* p = NULL;
+ // Some older GCC versions may issue a spurious waring in this or the next
+ // assertion statement. This warning should not be suppressed with
+ // static_cast since the test verifies the ability to use bare NULL as the
+ // expected parameter to the macro.
+ ASSERT_EQ(NULL, p);
+
+ // A failure.
+ static int n = 0;
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(NULL, &n),
+ "Value of: &n\n");
+}
+#endif // GTEST_CAN_COMPARE_NULL
+
+// Tests ASSERT_EQ(0, non_pointer). Since the literal 0 can be
+// treated as a null pointer by the compiler, we need to make sure
+// that ASSERT_EQ(0, non_pointer) isn't interpreted by Google Test as
+// ASSERT_EQ(static_cast<void*>(NULL), non_pointer).
+TEST(ExpectTest, ASSERT_EQ_0) {
+ int n = 0;
+
+ // A success.
+ ASSERT_EQ(0, n);
+
+ // A failure.
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(0, 5.6),
+ "Expected: 0");
+}
+
+// Tests ASSERT_NE.
+TEST(AssertionTest, ASSERT_NE) {
+ ASSERT_NE(6, 7);
+ EXPECT_FATAL_FAILURE(ASSERT_NE('a', 'a'),
+ "Expected: ('a') != ('a'), "
+ "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)");
+}
+
+// Tests ASSERT_LE.
+TEST(AssertionTest, ASSERT_LE) {
+ ASSERT_LE(2, 3);
+ ASSERT_LE(2, 2);
+ EXPECT_FATAL_FAILURE(ASSERT_LE(2, 0),
+ "Expected: (2) <= (0), actual: 2 vs 0");
+}
+
+// Tests ASSERT_LT.
+TEST(AssertionTest, ASSERT_LT) {
+ ASSERT_LT(2, 3);
+ EXPECT_FATAL_FAILURE(ASSERT_LT(2, 2),
+ "Expected: (2) < (2), actual: 2 vs 2");
+}
+
+// Tests ASSERT_GE.
+TEST(AssertionTest, ASSERT_GE) {
+ ASSERT_GE(2, 1);
+ ASSERT_GE(2, 2);
+ EXPECT_FATAL_FAILURE(ASSERT_GE(2, 3),
+ "Expected: (2) >= (3), actual: 2 vs 3");
+}
+
+// Tests ASSERT_GT.
+TEST(AssertionTest, ASSERT_GT) {
+ ASSERT_GT(2, 1);
+ EXPECT_FATAL_FAILURE(ASSERT_GT(2, 2),
+ "Expected: (2) > (2), actual: 2 vs 2");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+void ThrowNothing() {}
+
+// Tests ASSERT_THROW.
+TEST(AssertionTest, ASSERT_THROW) {
+ ASSERT_THROW(ThrowAnInteger(), int);
+
+#ifndef __BORLANDC__
+ // ICE's in C++Builder 2007 and 2009.
+ EXPECT_FATAL_FAILURE(
+ ASSERT_THROW(ThrowAnInteger(), bool),
+ "Expected: ThrowAnInteger() throws an exception of type bool.\n"
+ " Actual: it throws a different type.");
+#endif
+
+ EXPECT_FATAL_FAILURE(
+ ASSERT_THROW(ThrowNothing(), bool),
+ "Expected: ThrowNothing() throws an exception of type bool.\n"
+ " Actual: it throws nothing.");
+}
+
+// Tests ASSERT_NO_THROW.
+TEST(AssertionTest, ASSERT_NO_THROW) {
+ ASSERT_NO_THROW(ThrowNothing());
+ EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()),
+ "Expected: ThrowAnInteger() doesn't throw an exception."
+ "\n Actual: it throws.");
+}
+
+// Tests ASSERT_ANY_THROW.
+TEST(AssertionTest, ASSERT_ANY_THROW) {
+ ASSERT_ANY_THROW(ThrowAnInteger());
+ EXPECT_FATAL_FAILURE(
+ ASSERT_ANY_THROW(ThrowNothing()),
+ "Expected: ThrowNothing() throws an exception.\n"
+ " Actual: it doesn't.");
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Makes sure we deal with the precedence of <<. This test should
+// compile.
+TEST(AssertionTest, AssertPrecedence) {
+ ASSERT_EQ(1 < 2, true);
+ ASSERT_EQ(true && false, false);
+}
+
+// A subroutine used by the following test.
+void TestEq1(int x) {
+ ASSERT_EQ(1, x);
+}
+
+// Tests calling a test subroutine that's not part of a fixture.
+TEST(AssertionTest, NonFixtureSubroutine) {
+ EXPECT_FATAL_FAILURE(TestEq1(2),
+ "Value of: x");
+}
+
+// An uncopyable class.
+class Uncopyable {
+ public:
+ explicit Uncopyable(int a_value) : value_(a_value) {}
+
+ int value() const { return value_; }
+ bool operator==(const Uncopyable& rhs) const {
+ return value() == rhs.value();
+ }
+ private:
+ // This constructor deliberately has no implementation, as we don't
+ // want this class to be copyable.
+ Uncopyable(const Uncopyable&); // NOLINT
+
+ int value_;
+};
+
+::std::ostream& operator<<(::std::ostream& os, const Uncopyable& value) {
+ return os << value.value();
+}
+
+
+bool IsPositiveUncopyable(const Uncopyable& x) {
+ return x.value() > 0;
+}
+
+// A subroutine used by the following test.
+void TestAssertNonPositive() {
+ Uncopyable y(-1);
+ ASSERT_PRED1(IsPositiveUncopyable, y);
+}
+// A subroutine used by the following test.
+void TestAssertEqualsUncopyable() {
+ Uncopyable x(5);
+ Uncopyable y(-1);
+ ASSERT_EQ(x, y);
+}
+
+// Tests that uncopyable objects can be used in assertions.
+TEST(AssertionTest, AssertWorksWithUncopyableObject) {
+ Uncopyable x(5);
+ ASSERT_PRED1(IsPositiveUncopyable, x);
+ ASSERT_EQ(x, x);
+ EXPECT_FATAL_FAILURE(TestAssertNonPositive(),
+ "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1");
+ EXPECT_FATAL_FAILURE(TestAssertEqualsUncopyable(),
+ "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5");
+}
+
+// Tests that uncopyable objects can be used in expects.
+TEST(AssertionTest, ExpectWorksWithUncopyableObject) {
+ Uncopyable x(5);
+ EXPECT_PRED1(IsPositiveUncopyable, x);
+ Uncopyable y(-1);
+ EXPECT_NONFATAL_FAILURE(EXPECT_PRED1(IsPositiveUncopyable, y),
+ "IsPositiveUncopyable(y) evaluates to false, where\ny evaluates to -1");
+ EXPECT_EQ(x, x);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y),
+ "Value of: y\n Actual: -1\nExpected: x\nWhich is: 5");
+}
+
+
+// The version of gcc used in XCode 2.2 has a bug and doesn't allow
+// anonymous enums in assertions. Therefore the following test is not
+// done on Mac.
+// Sun Studio also rejects this code.
+#if !GTEST_OS_MAC && !defined(__SUNPRO_CC)
+
+// Tests using assertions with anonymous enums.
+enum {
+ CASE_A = -1,
+#if GTEST_OS_LINUX
+ // We want to test the case where the size of the anonymous enum is
+ // larger than sizeof(int), to make sure our implementation of the
+ // assertions doesn't truncate the enums. However, MSVC
+ // (incorrectly) doesn't allow an enum value to exceed the range of
+ // an int, so this has to be conditionally compiled.
+ //
+ // On Linux, CASE_B and CASE_A have the same value when truncated to
+ // int size. We want to test whether this will confuse the
+ // assertions.
+ CASE_B = testing::internal::kMaxBiggestInt,
+#else
+ CASE_B = INT_MAX,
+#endif // GTEST_OS_LINUX
+};
+
+TEST(AssertionTest, AnonymousEnum) {
+#if GTEST_OS_LINUX
+ EXPECT_EQ(static_cast<int>(CASE_A), static_cast<int>(CASE_B));
+#endif // GTEST_OS_LINUX
+
+ EXPECT_EQ(CASE_A, CASE_A);
+ EXPECT_NE(CASE_A, CASE_B);
+ EXPECT_LT(CASE_A, CASE_B);
+ EXPECT_LE(CASE_A, CASE_B);
+ EXPECT_GT(CASE_B, CASE_A);
+ EXPECT_GE(CASE_A, CASE_A);
+ EXPECT_NONFATAL_FAILURE(EXPECT_GE(CASE_A, CASE_B),
+ "(CASE_A) >= (CASE_B)");
+
+ ASSERT_EQ(CASE_A, CASE_A);
+ ASSERT_NE(CASE_A, CASE_B);
+ ASSERT_LT(CASE_A, CASE_B);
+ ASSERT_LE(CASE_A, CASE_B);
+ ASSERT_GT(CASE_B, CASE_A);
+ ASSERT_GE(CASE_A, CASE_A);
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(CASE_A, CASE_B),
+ "Value of: CASE_B");
+}
+
+#endif // !GTEST_OS_MAC && !defined(__SUNPRO_CC)
+
+#if GTEST_OS_WINDOWS
+
+static HRESULT UnexpectedHRESULTFailure() {
+ return E_UNEXPECTED;
+}
+
+static HRESULT OkHRESULTSuccess() {
+ return S_OK;
+}
+
+static HRESULT FalseHRESULTSuccess() {
+ return S_FALSE;
+}
+
+// HRESULT assertion tests test both zero and non-zero
+// success codes as well as failure message for each.
+//
+// Windows CE doesn't support message texts.
+TEST(HRESULTAssertionTest, EXPECT_HRESULT_SUCCEEDED) {
+ EXPECT_HRESULT_SUCCEEDED(S_OK);
+ EXPECT_HRESULT_SUCCEEDED(S_FALSE);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()),
+ "Expected: (UnexpectedHRESULTFailure()) succeeds.\n"
+ " Actual: 0x8000FFFF");
+}
+
+TEST(HRESULTAssertionTest, ASSERT_HRESULT_SUCCEEDED) {
+ ASSERT_HRESULT_SUCCEEDED(S_OK);
+ ASSERT_HRESULT_SUCCEEDED(S_FALSE);
+
+ EXPECT_FATAL_FAILURE(ASSERT_HRESULT_SUCCEEDED(UnexpectedHRESULTFailure()),
+ "Expected: (UnexpectedHRESULTFailure()) succeeds.\n"
+ " Actual: 0x8000FFFF");
+}
+
+TEST(HRESULTAssertionTest, EXPECT_HRESULT_FAILED) {
+ EXPECT_HRESULT_FAILED(E_UNEXPECTED);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(OkHRESULTSuccess()),
+ "Expected: (OkHRESULTSuccess()) fails.\n"
+ " Actual: 0x00000000");
+ EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(FalseHRESULTSuccess()),
+ "Expected: (FalseHRESULTSuccess()) fails.\n"
+ " Actual: 0x00000001");
+}
+
+TEST(HRESULTAssertionTest, ASSERT_HRESULT_FAILED) {
+ ASSERT_HRESULT_FAILED(E_UNEXPECTED);
+
+#ifndef __BORLANDC__
+ // ICE's in C++Builder 2007 and 2009.
+ EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(OkHRESULTSuccess()),
+ "Expected: (OkHRESULTSuccess()) fails.\n"
+ " Actual: 0x00000000");
+#endif
+ EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(FalseHRESULTSuccess()),
+ "Expected: (FalseHRESULTSuccess()) fails.\n"
+ " Actual: 0x00000001");
+}
+
+// Tests that streaming to the HRESULT macros works.
+TEST(HRESULTAssertionTest, Streaming) {
+ EXPECT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure";
+ ASSERT_HRESULT_SUCCEEDED(S_OK) << "unexpected failure";
+ EXPECT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure";
+ ASSERT_HRESULT_FAILED(E_UNEXPECTED) << "unexpected failure";
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure",
+ "expected failure");
+
+#ifndef __BORLANDC__
+ // ICE's in C++Builder 2007 and 2009.
+ EXPECT_FATAL_FAILURE(
+ ASSERT_HRESULT_SUCCEEDED(E_UNEXPECTED) << "expected failure",
+ "expected failure");
+#endif
+
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_HRESULT_FAILED(S_OK) << "expected failure",
+ "expected failure");
+
+ EXPECT_FATAL_FAILURE(
+ ASSERT_HRESULT_FAILED(S_OK) << "expected failure",
+ "expected failure");
+}
+
+#endif // GTEST_OS_WINDOWS
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true", "Unreachable code"
+#pragma option push -w-ccc -w-rch
+#endif
+
+// Tests that the assertion macros behave like single statements.
+TEST(AssertionSyntaxTest, BasicAssertionsBehavesLikeSingleStatement) {
+ if (AlwaysFalse())
+ ASSERT_TRUE(false) << "This should never be executed; "
+ "It's a compilation test only.";
+
+ if (AlwaysTrue())
+ EXPECT_FALSE(false);
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ASSERT_LT(1, 3);
+
+ if (AlwaysFalse())
+ ; // NOLINT
+ else
+ EXPECT_GT(3, 2) << "";
+}
+
+#if GTEST_HAS_EXCEPTIONS
+// Tests that the compiler will not complain about unreachable code in the
+// EXPECT_THROW/EXPECT_ANY_THROW/EXPECT_NO_THROW macros.
+TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
+ int n = 0;
+
+ EXPECT_THROW(throw 1, int);
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(n++, int), "");
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(throw 1, const char*), "");
+ EXPECT_NO_THROW(n++);
+ EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(throw 1), "");
+ EXPECT_ANY_THROW(throw 1);
+ EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(n++), "");
+}
+
+TEST(AssertionSyntaxTest, ExceptionAssertionsBehavesLikeSingleStatement) {
+ if (AlwaysFalse())
+ EXPECT_THROW(ThrowNothing(), bool);
+
+ if (AlwaysTrue())
+ EXPECT_THROW(ThrowAnInteger(), int);
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ EXPECT_NO_THROW(ThrowAnInteger());
+
+ if (AlwaysTrue())
+ EXPECT_NO_THROW(ThrowNothing());
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ EXPECT_ANY_THROW(ThrowNothing());
+
+ if (AlwaysTrue())
+ EXPECT_ANY_THROW(ThrowAnInteger());
+ else
+ ; // NOLINT
+}
+#endif // GTEST_HAS_EXCEPTIONS
+
+TEST(AssertionSyntaxTest, NoFatalFailureAssertionsBehavesLikeSingleStatement) {
+ if (AlwaysFalse())
+ EXPECT_NO_FATAL_FAILURE(FAIL()) << "This should never be executed. "
+ << "It's a compilation test only.";
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ASSERT_NO_FATAL_FAILURE(FAIL()) << "";
+ else
+ ; // NOLINT
+
+ if (AlwaysTrue())
+ EXPECT_NO_FATAL_FAILURE(SUCCEED());
+ else
+ ; // NOLINT
+
+ if (AlwaysFalse())
+ ; // NOLINT
+ else
+ ASSERT_NO_FATAL_FAILURE(SUCCEED());
+}
+
+// Tests that the assertion macros work well with switch statements.
+TEST(AssertionSyntaxTest, WorksWithSwitch) {
+ switch (0) {
+ case 1:
+ break;
+ default:
+ ASSERT_TRUE(true);
+ }
+
+ switch (0)
+ case 0:
+ EXPECT_FALSE(false) << "EXPECT_FALSE failed in switch case";
+
+ // Binary assertions are implemented using a different code path
+ // than the Boolean assertions. Hence we test them separately.
+ switch (0) {
+ case 1:
+ default:
+ ASSERT_EQ(1, 1) << "ASSERT_EQ failed in default switch handler";
+ }
+
+ switch (0)
+ case 0:
+ EXPECT_NE(1, 2);
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+void ThrowAString() {
+ throw "String";
+}
+
+// Test that the exception assertion macros compile and work with const
+// type qualifier.
+TEST(AssertionSyntaxTest, WorksWithConst) {
+ ASSERT_THROW(ThrowAString(), const char*);
+
+ EXPECT_THROW(ThrowAString(), const char*);
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+} // namespace
+
+namespace testing {
+
+// Tests that Google Test tracks SUCCEED*.
+TEST(SuccessfulAssertionTest, SUCCEED) {
+ SUCCEED();
+ SUCCEED() << "OK";
+ EXPECT_EQ(2, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+// Tests that Google Test doesn't track successful EXPECT_*.
+TEST(SuccessfulAssertionTest, EXPECT) {
+ EXPECT_TRUE(true);
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+// Tests that Google Test doesn't track successful EXPECT_STR*.
+TEST(SuccessfulAssertionTest, EXPECT_STR) {
+ EXPECT_STREQ("", "");
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+// Tests that Google Test doesn't track successful ASSERT_*.
+TEST(SuccessfulAssertionTest, ASSERT) {
+ ASSERT_TRUE(true);
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+// Tests that Google Test doesn't track successful ASSERT_STR*.
+TEST(SuccessfulAssertionTest, ASSERT_STR) {
+ ASSERT_STREQ("", "");
+ EXPECT_EQ(0, GetUnitTestImpl()->current_test_result()->total_part_count());
+}
+
+} // namespace testing
+
+namespace {
+
+// Tests EXPECT_TRUE.
+TEST(ExpectTest, EXPECT_TRUE) {
+ EXPECT_TRUE(2 > 1); // NOLINT
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 < 1),
+ "Value of: 2 < 1\n"
+ " Actual: false\n"
+ "Expected: true");
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(2 > 3),
+ "2 > 3");
+}
+
+// Tests EXPECT_TRUE(predicate) for predicates returning AssertionResult.
+TEST(ExpectTest, ExpectTrueWithAssertionResult) {
+ EXPECT_TRUE(ResultIsEven(2));
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEven(3)),
+ "Value of: ResultIsEven(3)\n"
+ " Actual: false (3 is odd)\n"
+ "Expected: true");
+ EXPECT_TRUE(ResultIsEvenNoExplanation(2));
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(ResultIsEvenNoExplanation(3)),
+ "Value of: ResultIsEvenNoExplanation(3)\n"
+ " Actual: false (3 is odd)\n"
+ "Expected: true");
+}
+
+// Tests EXPECT_FALSE.
+TEST(ExpectTest, EXPECT_FALSE) {
+ EXPECT_FALSE(2 < 1); // NOLINT
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 > 1),
+ "Value of: 2 > 1\n"
+ " Actual: true\n"
+ "Expected: false");
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(2 < 3),
+ "2 < 3");
+}
+
+// Tests EXPECT_FALSE(predicate) for predicates returning AssertionResult.
+TEST(ExpectTest, ExpectFalseWithAssertionResult) {
+ EXPECT_FALSE(ResultIsEven(3));
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEven(2)),
+ "Value of: ResultIsEven(2)\n"
+ " Actual: true (2 is even)\n"
+ "Expected: false");
+ EXPECT_FALSE(ResultIsEvenNoExplanation(3));
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(ResultIsEvenNoExplanation(2)),
+ "Value of: ResultIsEvenNoExplanation(2)\n"
+ " Actual: true\n"
+ "Expected: false");
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" supressed them
+#pragma option pop
+#endif
+
+// Tests EXPECT_EQ.
+TEST(ExpectTest, EXPECT_EQ) {
+ EXPECT_EQ(5, 2 + 3);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2*3),
+ "Value of: 2*3\n"
+ " Actual: 6\n"
+ "Expected: 5");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5, 2 - 3),
+ "2 - 3");
+}
+
+// Tests using EXPECT_EQ on double values. The purpose is to make
+// sure that the specialization we did for integer and anonymous enums
+// isn't used for double arguments.
+TEST(ExpectTest, EXPECT_EQ_Double) {
+ // A success.
+ EXPECT_EQ(5.6, 5.6);
+
+ // A failure.
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(5.1, 5.2),
+ "5.1");
+}
+
+#if GTEST_CAN_COMPARE_NULL
+// Tests EXPECT_EQ(NULL, pointer).
+TEST(ExpectTest, EXPECT_EQ_NULL) {
+ // A success.
+ const char* p = NULL;
+ // Some older GCC versions may issue a spurious waring in this or the next
+ // assertion statement. This warning should not be suppressed with
+ // static_cast since the test verifies the ability to use bare NULL as the
+ // expected parameter to the macro.
+ EXPECT_EQ(NULL, p);
+
+ // A failure.
+ int n = 0;
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(NULL, &n),
+ "Value of: &n\n");
+}
+#endif // GTEST_CAN_COMPARE_NULL
+
+// Tests EXPECT_EQ(0, non_pointer). Since the literal 0 can be
+// treated as a null pointer by the compiler, we need to make sure
+// that EXPECT_EQ(0, non_pointer) isn't interpreted by Google Test as
+// EXPECT_EQ(static_cast<void*>(NULL), non_pointer).
+TEST(ExpectTest, EXPECT_EQ_0) {
+ int n = 0;
+
+ // A success.
+ EXPECT_EQ(0, n);
+
+ // A failure.
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(0, 5.6),
+ "Expected: 0");
+}
+
+// Tests EXPECT_NE.
+TEST(ExpectTest, EXPECT_NE) {
+ EXPECT_NE(6, 7);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE('a', 'a'),
+ "Expected: ('a') != ('a'), "
+ "actual: 'a' (97, 0x61) vs 'a' (97, 0x61)");
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE(2, 2),
+ "2");
+ char* const p0 = NULL;
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE(p0, p0),
+ "p0");
+ // Only way to get the Nokia compiler to compile the cast
+ // is to have a separate void* variable first. Putting
+ // the two casts on the same line doesn't work, neither does
+ // a direct C-style to char*.
+ void* pv1 = (void*)0x1234; // NOLINT
+ char* const p1 = reinterpret_cast<char*>(pv1);
+ EXPECT_NONFATAL_FAILURE(EXPECT_NE(p1, p1),
+ "p1");
+}
+
+// Tests EXPECT_LE.
+TEST(ExpectTest, EXPECT_LE) {
+ EXPECT_LE(2, 3);
+ EXPECT_LE(2, 2);
+ EXPECT_NONFATAL_FAILURE(EXPECT_LE(2, 0),
+ "Expected: (2) <= (0), actual: 2 vs 0");
+ EXPECT_NONFATAL_FAILURE(EXPECT_LE(1.1, 0.9),
+ "(1.1) <= (0.9)");
+}
+
+// Tests EXPECT_LT.
+TEST(ExpectTest, EXPECT_LT) {
+ EXPECT_LT(2, 3);
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 2),
+ "Expected: (2) < (2), actual: 2 vs 2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1),
+ "(2) < (1)");
+}
+
+// Tests EXPECT_GE.
+TEST(ExpectTest, EXPECT_GE) {
+ EXPECT_GE(2, 1);
+ EXPECT_GE(2, 2);
+ EXPECT_NONFATAL_FAILURE(EXPECT_GE(2, 3),
+ "Expected: (2) >= (3), actual: 2 vs 3");
+ EXPECT_NONFATAL_FAILURE(EXPECT_GE(0.9, 1.1),
+ "(0.9) >= (1.1)");
+}
+
+// Tests EXPECT_GT.
+TEST(ExpectTest, EXPECT_GT) {
+ EXPECT_GT(2, 1);
+ EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 2),
+ "Expected: (2) > (2), actual: 2 vs 2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_GT(2, 3),
+ "(2) > (3)");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Tests EXPECT_THROW.
+TEST(ExpectTest, EXPECT_THROW) {
+ EXPECT_THROW(ThrowAnInteger(), int);
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool),
+ "Expected: ThrowAnInteger() throws an exception of "
+ "type bool.\n Actual: it throws a different type.");
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_THROW(ThrowNothing(), bool),
+ "Expected: ThrowNothing() throws an exception of type bool.\n"
+ " Actual: it throws nothing.");
+}
+
+// Tests EXPECT_NO_THROW.
+TEST(ExpectTest, EXPECT_NO_THROW) {
+ EXPECT_NO_THROW(ThrowNothing());
+ EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()),
+ "Expected: ThrowAnInteger() doesn't throw an "
+ "exception.\n Actual: it throws.");
+}
+
+// Tests EXPECT_ANY_THROW.
+TEST(ExpectTest, EXPECT_ANY_THROW) {
+ EXPECT_ANY_THROW(ThrowAnInteger());
+ EXPECT_NONFATAL_FAILURE(
+ EXPECT_ANY_THROW(ThrowNothing()),
+ "Expected: ThrowNothing() throws an exception.\n"
+ " Actual: it doesn't.");
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Make sure we deal with the precedence of <<.
+TEST(ExpectTest, ExpectPrecedence) {
+ EXPECT_EQ(1 < 2, true);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(true, true && false),
+ "Value of: true && false");
+}
+
+
+// Tests the StreamableToString() function.
+
+// Tests using StreamableToString() on a scalar.
+TEST(StreamableToStringTest, Scalar) {
+ EXPECT_STREQ("5", StreamableToString(5).c_str());
+}
+
+// Tests using StreamableToString() on a non-char pointer.
+TEST(StreamableToStringTest, Pointer) {
+ int n = 0;
+ int* p = &n;
+ EXPECT_STRNE("(null)", StreamableToString(p).c_str());
+}
+
+// Tests using StreamableToString() on a NULL non-char pointer.
+TEST(StreamableToStringTest, NullPointer) {
+ int* p = NULL;
+ EXPECT_STREQ("(null)", StreamableToString(p).c_str());
+}
+
+// Tests using StreamableToString() on a C string.
+TEST(StreamableToStringTest, CString) {
+ EXPECT_STREQ("Foo", StreamableToString("Foo").c_str());
+}
+
+// Tests using StreamableToString() on a NULL C string.
+TEST(StreamableToStringTest, NullCString) {
+ char* p = NULL;
+ EXPECT_STREQ("(null)", StreamableToString(p).c_str());
+}
+
+// Tests using streamable values as assertion messages.
+
+// Tests using std::string as an assertion message.
+TEST(StreamableTest, string) {
+ static const std::string str(
+ "This failure message is a std::string, and is expected.");
+ EXPECT_FATAL_FAILURE(FAIL() << str,
+ str.c_str());
+}
+
+// Tests that we can output strings containing embedded NULs.
+// Limited to Linux because we can only do this with std::string's.
+TEST(StreamableTest, stringWithEmbeddedNUL) {
+ static const char char_array_with_nul[] =
+ "Here's a NUL\0 and some more string";
+ static const std::string string_with_nul(char_array_with_nul,
+ sizeof(char_array_with_nul)
+ - 1); // drops the trailing NUL
+ EXPECT_FATAL_FAILURE(FAIL() << string_with_nul,
+ "Here's a NUL\\0 and some more string");
+}
+
+// Tests that we can output a NUL char.
+TEST(StreamableTest, NULChar) {
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ FAIL() << "A NUL" << '\0' << " and some more string";
+ }, "A NUL\\0 and some more string");
+}
+
+// Tests using int as an assertion message.
+TEST(StreamableTest, int) {
+ EXPECT_FATAL_FAILURE(FAIL() << 900913,
+ "900913");
+}
+
+// Tests using NULL char pointer as an assertion message.
+//
+// In MSVC, streaming a NULL char * causes access violation. Google Test
+// implemented a workaround (substituting "(null)" for NULL). This
+// tests whether the workaround works.
+TEST(StreamableTest, NullCharPtr) {
+ EXPECT_FATAL_FAILURE(FAIL() << static_cast<const char*>(NULL),
+ "(null)");
+}
+
+// Tests that basic IO manipulators (endl, ends, and flush) can be
+// streamed to testing::Message.
+TEST(StreamableTest, BasicIoManip) {
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ FAIL() << "Line 1." << std::endl
+ << "A NUL char " << std::ends << std::flush << " in line 2.";
+ }, "Line 1.\nA NUL char \\0 in line 2.");
+}
+
+// Tests the macros that haven't been covered so far.
+
+void AddFailureHelper(bool* aborted) {
+ *aborted = true;
+ ADD_FAILURE() << "Failure";
+ *aborted = false;
+}
+
+// Tests ADD_FAILURE.
+TEST(MacroTest, ADD_FAILURE) {
+ bool aborted = true;
+ EXPECT_NONFATAL_FAILURE(AddFailureHelper(&aborted),
+ "Failure");
+ EXPECT_FALSE(aborted);
+}
+
+// Tests FAIL.
+TEST(MacroTest, FAIL) {
+ EXPECT_FATAL_FAILURE(FAIL(),
+ "Failed");
+ EXPECT_FATAL_FAILURE(FAIL() << "Intentional failure.",
+ "Intentional failure.");
+}
+
+// Tests SUCCEED
+TEST(MacroTest, SUCCEED) {
+ SUCCEED();
+ SUCCEED() << "Explicit success.";
+}
+
+
+// Tests for EXPECT_EQ() and ASSERT_EQ().
+//
+// These tests fail *intentionally*, s.t. the failure messages can be
+// generated and tested.
+//
+// We have different tests for different argument types.
+
+// Tests using bool values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, Bool) {
+ EXPECT_EQ(true, true);
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(false, true),
+ "Value of: true");
+}
+
+// Tests using int values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, Int) {
+ ASSERT_EQ(32, 32);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(32, 33),
+ "33");
+}
+
+// Tests using time_t values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, Time_T) {
+ EXPECT_EQ(static_cast<time_t>(0),
+ static_cast<time_t>(0));
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast<time_t>(0),
+ static_cast<time_t>(1234)),
+ "1234");
+}
+
+// Tests using char values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, Char) {
+ ASSERT_EQ('z', 'z');
+ const char ch = 'b';
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ('\0', ch),
+ "ch");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ('a', ch),
+ "ch");
+}
+
+// Tests using wchar_t values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, WideChar) {
+ EXPECT_EQ(L'b', L'b');
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'\0', L'x'),
+ "Value of: L'x'\n"
+ " Actual: L'x' (120, 0x78)\n"
+ "Expected: L'\0'\n"
+ "Which is: L'\0' (0, 0x0)");
+
+ static wchar_t wchar;
+ wchar = L'b';
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'a', wchar),
+ "wchar");
+ wchar = L'\x8119';
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(L'\x8120', wchar),
+ "Value of: wchar");
+}
+
+// Tests using ::std::string values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, StdString) {
+ // Compares a const char* to an std::string that has identical
+ // content.
+ ASSERT_EQ("Test", ::std::string("Test"));
+
+ // Compares two identical std::strings.
+ static const ::std::string str1("A * in the middle");
+ static const ::std::string str2(str1);
+ EXPECT_EQ(str1, str2);
+
+ // Compares a const char* to an std::string that has different
+ // content
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ("Test", ::std::string("test")),
+ "::std::string(\"test\")");
+
+ // Compares an std::string to a char* that has different content.
+ char* const p1 = const_cast<char*>("foo");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::std::string("bar"), p1),
+ "p1");
+
+ // Compares two std::strings that have different contents, one of
+ // which having a NUL character in the middle. This should fail.
+ static ::std::string str3(str1);
+ str3.at(2) = '\0';
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(str1, str3),
+ "Value of: str3\n"
+ " Actual: \"A \\0 in the middle\"");
+}
+
+#if GTEST_HAS_STD_WSTRING
+
+// Tests using ::std::wstring values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, StdWideString) {
+ // Compares an std::wstring to a const wchar_t* that has identical
+ // content.
+ EXPECT_EQ(::std::wstring(L"Test\x8119"), L"Test\x8119");
+
+ // Compares two identical std::wstrings.
+ const ::std::wstring wstr1(L"A * in the middle");
+ const ::std::wstring wstr2(wstr1);
+ ASSERT_EQ(wstr1, wstr2);
+
+ // Compares an std::wstring to a const wchar_t* that has different
+ // content.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_EQ(::std::wstring(L"Test\x8119"), L"Test\x8120");
+ }, "L\"Test\\x8120\"");
+
+ // Compares two std::wstrings that have different contents, one of
+ // which having a NUL character in the middle.
+ ::std::wstring wstr3(wstr1);
+ wstr3.at(2) = L'\0';
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(wstr1, wstr3),
+ "wstr3");
+
+ // Compares a wchar_t* to an std::wstring that has different
+ // content.
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_EQ(const_cast<wchar_t*>(L"foo"), ::std::wstring(L"bar"));
+ }, "");
+}
+
+#endif // GTEST_HAS_STD_WSTRING
+
+#if GTEST_HAS_GLOBAL_STRING
+// Tests using ::string values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, GlobalString) {
+ // Compares a const char* to a ::string that has identical content.
+ EXPECT_EQ("Test", ::string("Test"));
+
+ // Compares two identical ::strings.
+ const ::string str1("A * in the middle");
+ const ::string str2(str1);
+ ASSERT_EQ(str1, str2);
+
+ // Compares a ::string to a const char* that has different content.
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(::string("Test"), "test"),
+ "test");
+
+ // Compares two ::strings that have different contents, one of which
+ // having a NUL character in the middle.
+ ::string str3(str1);
+ str3.at(2) = '\0';
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(str1, str3),
+ "str3");
+
+ // Compares a ::string to a char* that has different content.
+ EXPECT_FATAL_FAILURE({ // NOLINT
+ ASSERT_EQ(::string("bar"), const_cast<char*>("foo"));
+ }, "");
+}
+
+#endif // GTEST_HAS_GLOBAL_STRING
+
+#if GTEST_HAS_GLOBAL_WSTRING
+
+// Tests using ::wstring values in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, GlobalWideString) {
+ // Compares a const wchar_t* to a ::wstring that has identical content.
+ ASSERT_EQ(L"Test\x8119", ::wstring(L"Test\x8119"));
+
+ // Compares two identical ::wstrings.
+ static const ::wstring wstr1(L"A * in the middle");
+ static const ::wstring wstr2(wstr1);
+ EXPECT_EQ(wstr1, wstr2);
+
+ // Compares a const wchar_t* to a ::wstring that has different
+ // content.
+ EXPECT_NONFATAL_FAILURE({ // NOLINT
+ EXPECT_EQ(L"Test\x8120", ::wstring(L"Test\x8119"));
+ }, "Test\\x8119");
+
+ // Compares a wchar_t* to a ::wstring that has different content.
+ wchar_t* const p1 = const_cast<wchar_t*>(L"foo");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, ::wstring(L"bar")),
+ "bar");
+
+ // Compares two ::wstrings that have different contents, one of which
+ // having a NUL character in the middle.
+ static ::wstring wstr3;
+ wstr3 = wstr1;
+ wstr3.at(2) = L'\0';
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(wstr1, wstr3),
+ "wstr3");
+}
+
+#endif // GTEST_HAS_GLOBAL_WSTRING
+
+// Tests using char pointers in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, CharPointer) {
+ char* const p0 = NULL;
+ // Only way to get the Nokia compiler to compile the cast
+ // is to have a separate void* variable first. Putting
+ // the two casts on the same line doesn't work, neither does
+ // a direct C-style to char*.
+ void* pv1 = (void*)0x1234; // NOLINT
+ void* pv2 = (void*)0xABC0; // NOLINT
+ char* const p1 = reinterpret_cast<char*>(pv1);
+ char* const p2 = reinterpret_cast<char*>(pv2);
+ ASSERT_EQ(p1, p1);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2),
+ "Value of: p2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2),
+ "p2");
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(reinterpret_cast<char*>(0x1234),
+ reinterpret_cast<char*>(0xABC0)),
+ "ABC0");
+}
+
+// Tests using wchar_t pointers in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, WideCharPointer) {
+ wchar_t* const p0 = NULL;
+ // Only way to get the Nokia compiler to compile the cast
+ // is to have a separate void* variable first. Putting
+ // the two casts on the same line doesn't work, neither does
+ // a direct C-style to char*.
+ void* pv1 = (void*)0x1234; // NOLINT
+ void* pv2 = (void*)0xABC0; // NOLINT
+ wchar_t* const p1 = reinterpret_cast<wchar_t*>(pv1);
+ wchar_t* const p2 = reinterpret_cast<wchar_t*>(pv2);
+ EXPECT_EQ(p0, p0);
+
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2),
+ "Value of: p2");
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2),
+ "p2");
+ void* pv3 = (void*)0x1234; // NOLINT
+ void* pv4 = (void*)0xABC0; // NOLINT
+ const wchar_t* p3 = reinterpret_cast<const wchar_t*>(pv3);
+ const wchar_t* p4 = reinterpret_cast<const wchar_t*>(pv4);
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p3, p4),
+ "p4");
+}
+
+// Tests using other types of pointers in {EXPECT|ASSERT}_EQ.
+TEST(EqAssertionTest, OtherPointer) {
+ ASSERT_EQ(static_cast<const int*>(NULL),
+ static_cast<const int*>(NULL));
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast<const int*>(NULL),
+ reinterpret_cast<const int*>(0x1234)),
+ "0x1234");
+}
+
+// Tests the FRIEND_TEST macro.
+
+// This class has a private member we want to test. We will test it
+// both in a TEST and in a TEST_F.
+class Foo {
+ public:
+ Foo() {}
+
+ private:
+ int Bar() const { return 1; }
+
+ // Declares the friend tests that can access the private member
+ // Bar().
+ FRIEND_TEST(FRIEND_TEST_Test, TEST);
+ FRIEND_TEST(FRIEND_TEST_Test2, TEST_F);
+};
+
+// Tests that the FRIEND_TEST declaration allows a TEST to access a
+// class's private members. This should compile.
+TEST(FRIEND_TEST_Test, TEST) {
+ ASSERT_EQ(1, Foo().Bar());
+}
+
+// The fixture needed to test using FRIEND_TEST with TEST_F.
+class FRIEND_TEST_Test2 : public Test {
+ protected:
+ Foo foo;
+};
+
+// Tests that the FRIEND_TEST declaration allows a TEST_F to access a
+// class's private members. This should compile.
+TEST_F(FRIEND_TEST_Test2, TEST_F) {
+ ASSERT_EQ(1, foo.Bar());
+}
+
+// Tests the life cycle of Test objects.
+
+// The test fixture for testing the life cycle of Test objects.
+//
+// This class counts the number of live test objects that uses this
+// fixture.
+class TestLifeCycleTest : public Test {
+ protected:
+ // Constructor. Increments the number of test objects that uses
+ // this fixture.
+ TestLifeCycleTest() { count_++; }
+
+ // Destructor. Decrements the number of test objects that uses this
+ // fixture.
+ ~TestLifeCycleTest() { count_--; }
+
+ // Returns the number of live test objects that uses this fixture.
+ int count() const { return count_; }
+
+ private:
+ static int count_;
+};
+
+int TestLifeCycleTest::count_ = 0;
+
+// Tests the life cycle of test objects.
+TEST_F(TestLifeCycleTest, Test1) {
+ // There should be only one test object in this test case that's
+ // currently alive.
+ ASSERT_EQ(1, count());
+}
+
+// Tests the life cycle of test objects.
+TEST_F(TestLifeCycleTest, Test2) {
+ // After Test1 is done and Test2 is started, there should still be
+ // only one live test object, as the object for Test1 should've been
+ // deleted.
+ ASSERT_EQ(1, count());
+}
+
+} // namespace
+
+// Tests that the copy constructor works when it is NOT optimized away by
+// the compiler.
+TEST(AssertionResultTest, CopyConstructorWorksWhenNotOptimied) {
+ // Checks that the copy constructor doesn't try to dereference NULL pointers
+ // in the source object.
+ AssertionResult r1 = AssertionSuccess();
+ AssertionResult r2 = r1;
+ // The following line is added to prevent the compiler from optimizing
+ // away the constructor call.
+ r1 << "abc";
+
+ AssertionResult r3 = r1;
+ EXPECT_EQ(static_cast<bool>(r3), static_cast<bool>(r1));
+ EXPECT_STREQ("abc", r1.message());
+}
+
+// Tests that AssertionSuccess and AssertionFailure construct
+// AssertionResult objects as expected.
+TEST(AssertionResultTest, ConstructionWorks) {
+ AssertionResult r1 = AssertionSuccess();
+ EXPECT_TRUE(r1);
+ EXPECT_STREQ("", r1.message());
+
+ AssertionResult r2 = AssertionSuccess() << "abc";
+ EXPECT_TRUE(r2);
+ EXPECT_STREQ("abc", r2.message());
+
+ AssertionResult r3 = AssertionFailure();
+ EXPECT_FALSE(r3);
+ EXPECT_STREQ("", r3.message());
+
+ AssertionResult r4 = AssertionFailure() << "def";
+ EXPECT_FALSE(r4);
+ EXPECT_STREQ("def", r4.message());
+
+ AssertionResult r5 = AssertionFailure(Message() << "ghi");
+ EXPECT_FALSE(r5);
+ EXPECT_STREQ("ghi", r5.message());
+}
+
+// Tests that the negation fips the predicate result but keeps the message.
+TEST(AssertionResultTest, NegationWorks) {
+ AssertionResult r1 = AssertionSuccess() << "abc";
+ EXPECT_FALSE(!r1);
+ EXPECT_STREQ("abc", (!r1).message());
+
+ AssertionResult r2 = AssertionFailure() << "def";
+ EXPECT_TRUE(!r2);
+ EXPECT_STREQ("def", (!r2).message());
+}
+
+TEST(AssertionResultTest, StreamingWorks) {
+ AssertionResult r = AssertionSuccess();
+ r << "abc" << 'd' << 0 << true;
+ EXPECT_STREQ("abcd0true", r.message());
+}
+
+// Tests streaming a user type whose definition and operator << are
+// both in the global namespace.
+class Base {
+ public:
+ explicit Base(int an_x) : x_(an_x) {}
+ int x() const { return x_; }
+ private:
+ int x_;
+};
+std::ostream& operator<<(std::ostream& os,
+ const Base& val) {
+ return os << val.x();
+}
+std::ostream& operator<<(std::ostream& os,
+ const Base* pointer) {
+ return os << "(" << pointer->x() << ")";
+}
+
+TEST(MessageTest, CanStreamUserTypeInGlobalNameSpace) {
+ Message msg;
+ Base a(1);
+
+ msg << a << &a; // Uses ::operator<<.
+ EXPECT_STREQ("1(1)", msg.GetString().c_str());
+}
+
+// Tests streaming a user type whose definition and operator<< are
+// both in an unnamed namespace.
+namespace {
+class MyTypeInUnnamedNameSpace : public Base {
+ public:
+ explicit MyTypeInUnnamedNameSpace(int an_x): Base(an_x) {}
+};
+std::ostream& operator<<(std::ostream& os,
+ const MyTypeInUnnamedNameSpace& val) {
+ return os << val.x();
+}
+std::ostream& operator<<(std::ostream& os,
+ const MyTypeInUnnamedNameSpace* pointer) {
+ return os << "(" << pointer->x() << ")";
+}
+} // namespace
+
+TEST(MessageTest, CanStreamUserTypeInUnnamedNameSpace) {
+ Message msg;
+ MyTypeInUnnamedNameSpace a(1);
+
+ msg << a << &a; // Uses <unnamed_namespace>::operator<<.
+ EXPECT_STREQ("1(1)", msg.GetString().c_str());
+}
+
+// Tests streaming a user type whose definition and operator<< are
+// both in a user namespace.
+namespace namespace1 {
+class MyTypeInNameSpace1 : public Base {
+ public:
+ explicit MyTypeInNameSpace1(int an_x): Base(an_x) {}
+};
+std::ostream& operator<<(std::ostream& os,
+ const MyTypeInNameSpace1& val) {
+ return os << val.x();
+}
+std::ostream& operator<<(std::ostream& os,
+ const MyTypeInNameSpace1* pointer) {
+ return os << "(" << pointer->x() << ")";
+}
+} // namespace namespace1
+
+TEST(MessageTest, CanStreamUserTypeInUserNameSpace) {
+ Message msg;
+ namespace1::MyTypeInNameSpace1 a(1);
+
+ msg << a << &a; // Uses namespace1::operator<<.
+ EXPECT_STREQ("1(1)", msg.GetString().c_str());
+}
+
+// Tests streaming a user type whose definition is in a user namespace
+// but whose operator<< is in the global namespace.
+namespace namespace2 {
+class MyTypeInNameSpace2 : public ::Base {
+ public:
+ explicit MyTypeInNameSpace2(int an_x): Base(an_x) {}
+};
+} // namespace namespace2
+std::ostream& operator<<(std::ostream& os,
+ const namespace2::MyTypeInNameSpace2& val) {
+ return os << val.x();
+}
+std::ostream& operator<<(std::ostream& os,
+ const namespace2::MyTypeInNameSpace2* pointer) {
+ return os << "(" << pointer->x() << ")";
+}
+
+TEST(MessageTest, CanStreamUserTypeInUserNameSpaceWithStreamOperatorInGlobal) {
+ Message msg;
+ namespace2::MyTypeInNameSpace2 a(1);
+
+ msg << a << &a; // Uses ::operator<<.
+ EXPECT_STREQ("1(1)", msg.GetString().c_str());
+}
+
+// Tests streaming NULL pointers to testing::Message.
+TEST(MessageTest, NullPointers) {
+ Message msg;
+ char* const p1 = NULL;
+ unsigned char* const p2 = NULL;
+ int* p3 = NULL;
+ double* p4 = NULL;
+ bool* p5 = NULL;
+ Message* p6 = NULL;
+
+ msg << p1 << p2 << p3 << p4 << p5 << p6;
+ ASSERT_STREQ("(null)(null)(null)(null)(null)(null)",
+ msg.GetString().c_str());
+}
+
+// Tests streaming wide strings to testing::Message.
+TEST(MessageTest, WideStrings) {
+ // Streams a NULL of type const wchar_t*.
+ const wchar_t* const_wstr = NULL;
+ EXPECT_STREQ("(null)",
+ (Message() << const_wstr).GetString().c_str());
+
+ // Streams a NULL of type wchar_t*.
+ wchar_t* wstr = NULL;
+ EXPECT_STREQ("(null)",
+ (Message() << wstr).GetString().c_str());
+
+ // Streams a non-NULL of type const wchar_t*.
+ const_wstr = L"abc\x8119";
+ EXPECT_STREQ("abc\xe8\x84\x99",
+ (Message() << const_wstr).GetString().c_str());
+
+ // Streams a non-NULL of type wchar_t*.
+ wstr = const_cast<wchar_t*>(const_wstr);
+ EXPECT_STREQ("abc\xe8\x84\x99",
+ (Message() << wstr).GetString().c_str());
+}
+
+
+// This line tests that we can define tests in the testing namespace.
+namespace testing {
+
+// Tests the TestInfo class.
+
+class TestInfoTest : public Test {
+ protected:
+ static const TestInfo* GetTestInfo(const char* test_name) {
+ const TestCase* const test_case = GetUnitTestImpl()->
+ GetTestCase("TestInfoTest", "", NULL, NULL);
+
+ for (int i = 0; i < test_case->total_test_count(); ++i) {
+ const TestInfo* const test_info = test_case->GetTestInfo(i);
+ if (strcmp(test_name, test_info->name()) == 0)
+ return test_info;
+ }
+ return NULL;
+ }
+
+ static const TestResult* GetTestResult(
+ const TestInfo* test_info) {
+ return test_info->result();
+ }
+};
+
+// Tests TestInfo::test_case_name() and TestInfo::name().
+TEST_F(TestInfoTest, Names) {
+ const TestInfo* const test_info = GetTestInfo("Names");
+
+ ASSERT_STREQ("TestInfoTest", test_info->test_case_name());
+ ASSERT_STREQ("Names", test_info->name());
+}
+
+// Tests TestInfo::result().
+TEST_F(TestInfoTest, result) {
+ const TestInfo* const test_info = GetTestInfo("result");
+
+ // Initially, there is no TestPartResult for this test.
+ ASSERT_EQ(0, GetTestResult(test_info)->total_part_count());
+
+ // After the previous assertion, there is still none.
+ ASSERT_EQ(0, GetTestResult(test_info)->total_part_count());
+}
+
+// Tests setting up and tearing down a test case.
+
+class SetUpTestCaseTest : public Test {
+ protected:
+ // This will be called once before the first test in this test case
+ // is run.
+ static void SetUpTestCase() {
+ printf("Setting up the test case . . .\n");
+
+ // Initializes some shared resource. In this simple example, we
+ // just create a C string. More complex stuff can be done if
+ // desired.
+ shared_resource_ = "123";
+
+ // Increments the number of test cases that have been set up.
+ counter_++;
+
+ // SetUpTestCase() should be called only once.
+ EXPECT_EQ(1, counter_);
+ }
+
+ // This will be called once after the last test in this test case is
+ // run.
+ static void TearDownTestCase() {
+ printf("Tearing down the test case . . .\n");
+
+ // Decrements the number of test cases that have been set up.
+ counter_--;
+
+ // TearDownTestCase() should be called only once.
+ EXPECT_EQ(0, counter_);
+
+ // Cleans up the shared resource.
+ shared_resource_ = NULL;
+ }
+
+ // This will be called before each test in this test case.
+ virtual void SetUp() {
+ // SetUpTestCase() should be called only once, so counter_ should
+ // always be 1.
+ EXPECT_EQ(1, counter_);
+ }
+
+ // Number of test cases that have been set up.
+ static int counter_;
+
+ // Some resource to be shared by all tests in this test case.
+ static const char* shared_resource_;
+};
+
+int SetUpTestCaseTest::counter_ = 0;
+const char* SetUpTestCaseTest::shared_resource_ = NULL;
+
+// A test that uses the shared resource.
+TEST_F(SetUpTestCaseTest, Test1) {
+ EXPECT_STRNE(NULL, shared_resource_);
+}
+
+// Another test that uses the shared resource.
+TEST_F(SetUpTestCaseTest, Test2) {
+ EXPECT_STREQ("123", shared_resource_);
+}
+
+// The InitGoogleTestTest test case tests testing::InitGoogleTest().
+
+// The Flags struct stores a copy of all Google Test flags.
+struct Flags {
+ // Constructs a Flags struct where each flag has its default value.
+ Flags() : also_run_disabled_tests(false),
+ break_on_failure(false),
+ catch_exceptions(false),
+ death_test_use_fork(false),
+ filter(""),
+ list_tests(false),
+ output(""),
+ print_time(true),
+ random_seed(0),
+ repeat(1),
+ shuffle(false),
+ stack_trace_depth(kMaxStackTraceDepth),
+ throw_on_failure(false) {}
+
+ // Factory methods.
+
+ // Creates a Flags struct where the gtest_also_run_disabled_tests flag has
+ // the given value.
+ static Flags AlsoRunDisabledTests(bool also_run_disabled_tests) {
+ Flags flags;
+ flags.also_run_disabled_tests = also_run_disabled_tests;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_break_on_failure flag has
+ // the given value.
+ static Flags BreakOnFailure(bool break_on_failure) {
+ Flags flags;
+ flags.break_on_failure = break_on_failure;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_catch_exceptions flag has
+ // the given value.
+ static Flags CatchExceptions(bool catch_exceptions) {
+ Flags flags;
+ flags.catch_exceptions = catch_exceptions;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_death_test_use_fork flag has
+ // the given value.
+ static Flags DeathTestUseFork(bool death_test_use_fork) {
+ Flags flags;
+ flags.death_test_use_fork = death_test_use_fork;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_filter flag has the given
+ // value.
+ static Flags Filter(const char* filter) {
+ Flags flags;
+ flags.filter = filter;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_list_tests flag has the
+ // given value.
+ static Flags ListTests(bool list_tests) {
+ Flags flags;
+ flags.list_tests = list_tests;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_output flag has the given
+ // value.
+ static Flags Output(const char* output) {
+ Flags flags;
+ flags.output = output;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_print_time flag has the given
+ // value.
+ static Flags PrintTime(bool print_time) {
+ Flags flags;
+ flags.print_time = print_time;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_random_seed flag has
+ // the given value.
+ static Flags RandomSeed(Int32 random_seed) {
+ Flags flags;
+ flags.random_seed = random_seed;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_repeat flag has the given
+ // value.
+ static Flags Repeat(Int32 repeat) {
+ Flags flags;
+ flags.repeat = repeat;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_shuffle flag has
+ // the given value.
+ static Flags Shuffle(bool shuffle) {
+ Flags flags;
+ flags.shuffle = shuffle;
+ return flags;
+ }
+
+ // Creates a Flags struct where the GTEST_FLAG(stack_trace_depth) flag has
+ // the given value.
+ static Flags StackTraceDepth(Int32 stack_trace_depth) {
+ Flags flags;
+ flags.stack_trace_depth = stack_trace_depth;
+ return flags;
+ }
+
+ // Creates a Flags struct where the gtest_throw_on_failure flag has
+ // the given value.
+ static Flags ThrowOnFailure(bool throw_on_failure) {
+ Flags flags;
+ flags.throw_on_failure = throw_on_failure;
+ return flags;
+ }
+
+ // These fields store the flag values.
+ bool also_run_disabled_tests;
+ bool break_on_failure;
+ bool catch_exceptions;
+ bool death_test_use_fork;
+ const char* filter;
+ bool list_tests;
+ const char* output;
+ bool print_time;
+ Int32 random_seed;
+ Int32 repeat;
+ bool shuffle;
+ Int32 stack_trace_depth;
+ bool throw_on_failure;
+};
+
+// Fixture for testing InitGoogleTest().
+class InitGoogleTestTest : public Test {
+ protected:
+ // Clears the flags before each test.
+ virtual void SetUp() {
+ GTEST_FLAG(also_run_disabled_tests) = false;
+ GTEST_FLAG(break_on_failure) = false;
+ GTEST_FLAG(catch_exceptions) = false;
+ GTEST_FLAG(death_test_use_fork) = false;
+ GTEST_FLAG(filter) = "";
+ GTEST_FLAG(list_tests) = false;
+ GTEST_FLAG(output) = "";
+ GTEST_FLAG(print_time) = true;
+ GTEST_FLAG(random_seed) = 0;
+ GTEST_FLAG(repeat) = 1;
+ GTEST_FLAG(shuffle) = false;
+ GTEST_FLAG(stack_trace_depth) = kMaxStackTraceDepth;
+ GTEST_FLAG(throw_on_failure) = false;
+ }
+
+ // Asserts that two narrow or wide string arrays are equal.
+ template <typename CharType>
+ static void AssertStringArrayEq(size_t size1, CharType** array1,
+ size_t size2, CharType** array2) {
+ ASSERT_EQ(size1, size2) << " Array sizes different.";
+
+ for (size_t i = 0; i != size1; i++) {
+ ASSERT_STREQ(array1[i], array2[i]) << " where i == " << i;
+ }
+ }
+
+ // Verifies that the flag values match the expected values.
+ static void CheckFlags(const Flags& expected) {
+ EXPECT_EQ(expected.also_run_disabled_tests,
+ GTEST_FLAG(also_run_disabled_tests));
+ EXPECT_EQ(expected.break_on_failure, GTEST_FLAG(break_on_failure));
+ EXPECT_EQ(expected.catch_exceptions, GTEST_FLAG(catch_exceptions));
+ EXPECT_EQ(expected.death_test_use_fork, GTEST_FLAG(death_test_use_fork));
+ EXPECT_STREQ(expected.filter, GTEST_FLAG(filter).c_str());
+ EXPECT_EQ(expected.list_tests, GTEST_FLAG(list_tests));
+ EXPECT_STREQ(expected.output, GTEST_FLAG(output).c_str());
+ EXPECT_EQ(expected.print_time, GTEST_FLAG(print_time));
+ EXPECT_EQ(expected.random_seed, GTEST_FLAG(random_seed));
+ EXPECT_EQ(expected.repeat, GTEST_FLAG(repeat));
+ EXPECT_EQ(expected.shuffle, GTEST_FLAG(shuffle));
+ EXPECT_EQ(expected.throw_on_failure, GTEST_FLAG(throw_on_failure));
+ EXPECT_EQ(expected.stack_trace_depth, GTEST_FLAG(stack_trace_depth));
+ }
+
+ // Parses a command line (specified by argc1 and argv1), then
+ // verifies that the flag values are expected and that the
+ // recognized flags are removed from the command line.
+ template <typename CharType>
+ static void TestParsingFlags(int argc1, const CharType** argv1,
+ int argc2, const CharType** argv2,
+ const Flags& expected, bool should_print_help) {
+ const bool saved_help_flag = ::testing::internal::g_help_flag;
+ ::testing::internal::g_help_flag = false;
+
+#if GTEST_HAS_STREAM_REDIRECTION_
+ CaptureStdout();
+#endif // GTEST_HAS_STREAM_REDIRECTION_
+
+ // Parses the command line.
+ internal::ParseGoogleTestFlagsOnly(&argc1, const_cast<CharType**>(argv1));
+
+#if GTEST_HAS_STREAM_REDIRECTION_
+ const String captured_stdout = GetCapturedStdout();
+#endif // GTEST_HAS_STREAM_REDIRECTION_
+
+ // Verifies the flag values.
+ CheckFlags(expected);
+
+ // Verifies that the recognized flags are removed from the command
+ // line.
+ AssertStringArrayEq(argc1 + 1, argv1, argc2 + 1, argv2);
+
+ // ParseGoogleTestFlagsOnly should neither set g_help_flag nor print the
+ // help message for the flags it recognizes.
+ EXPECT_EQ(should_print_help, ::testing::internal::g_help_flag);
+
+#if GTEST_HAS_STREAM_REDIRECTION_
+ const char* const expected_help_fragment =
+ "This program contains tests written using";
+ if (should_print_help) {
+ EXPECT_PRED_FORMAT2(IsSubstring, expected_help_fragment, captured_stdout);
+ } else {
+ EXPECT_PRED_FORMAT2(IsNotSubstring,
+ expected_help_fragment, captured_stdout);
+ }
+#endif // GTEST_HAS_STREAM_REDIRECTION_
+
+ ::testing::internal::g_help_flag = saved_help_flag;
+ }
+
+ // This macro wraps TestParsingFlags s.t. the user doesn't need
+ // to specify the array sizes.
+#define GTEST_TEST_PARSING_FLAGS_(argv1, argv2, expected, should_print_help) \
+ TestParsingFlags(sizeof(argv1)/sizeof(*argv1) - 1, argv1, \
+ sizeof(argv2)/sizeof(*argv2) - 1, argv2, \
+ expected, should_print_help)
+};
+
+// Tests parsing an empty command line.
+TEST_F(InitGoogleTestTest, Empty) {
+ const char* argv[] = {
+ NULL
+ };
+
+ const char* argv2[] = {
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false);
+}
+
+// Tests parsing a command line that has no flag.
+TEST_F(InitGoogleTestTest, NoFlag) {
+ const char* argv[] = {
+ "foo.exe",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false);
+}
+
+// Tests parsing a bad --gtest_filter flag.
+TEST_F(InitGoogleTestTest, FilterBad) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_filter",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ "--gtest_filter",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), true);
+}
+
+// Tests parsing an empty --gtest_filter flag.
+TEST_F(InitGoogleTestTest, FilterEmpty) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_filter=",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter(""), false);
+}
+
+// Tests parsing a non-empty --gtest_filter flag.
+TEST_F(InitGoogleTestTest, FilterNonEmpty) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_filter=abc",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false);
+}
+
+// Tests parsing --gtest_break_on_failure.
+TEST_F(InitGoogleTestTest, BreakOnFailureWithoutValue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure",
+ NULL
+};
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false);
+}
+
+// Tests parsing --gtest_break_on_failure=0.
+TEST_F(InitGoogleTestTest, BreakOnFailureFalse_0) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false);
+}
+
+// Tests parsing --gtest_break_on_failure=f.
+TEST_F(InitGoogleTestTest, BreakOnFailureFalse_f) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure=f",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false);
+}
+
+// Tests parsing --gtest_break_on_failure=F.
+TEST_F(InitGoogleTestTest, BreakOnFailureFalse_F) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure=F",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(false), false);
+}
+
+// Tests parsing a --gtest_break_on_failure flag that has a "true"
+// definition.
+TEST_F(InitGoogleTestTest, BreakOnFailureTrue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::BreakOnFailure(true), false);
+}
+
+// Tests parsing --gtest_catch_exceptions.
+TEST_F(InitGoogleTestTest, CatchExceptions) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_catch_exceptions",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::CatchExceptions(true), false);
+}
+
+// Tests parsing --gtest_death_test_use_fork.
+TEST_F(InitGoogleTestTest, DeathTestUseFork) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_death_test_use_fork",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::DeathTestUseFork(true), false);
+}
+
+// Tests having the same flag twice with different values. The
+// expected behavior is that the one coming last takes precedence.
+TEST_F(InitGoogleTestTest, DuplicatedFlags) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_filter=a",
+ "--gtest_filter=b",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("b"), false);
+}
+
+// Tests having an unrecognized flag on the command line.
+TEST_F(InitGoogleTestTest, UnrecognizedFlag) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_break_on_failure",
+ "bar", // Unrecognized by Google Test.
+ "--gtest_filter=b",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ "bar",
+ NULL
+ };
+
+ Flags flags;
+ flags.break_on_failure = true;
+ flags.filter = "b";
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, flags, false);
+}
+
+// Tests having a --gtest_list_tests flag
+TEST_F(InitGoogleTestTest, ListTestsFlag) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false);
+}
+
+// Tests having a --gtest_list_tests flag with a "true" value
+TEST_F(InitGoogleTestTest, ListTestsTrue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(true), false);
+}
+
+// Tests having a --gtest_list_tests flag with a "false" value
+TEST_F(InitGoogleTestTest, ListTestsFalse) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false);
+}
+
+// Tests parsing --gtest_list_tests=f.
+TEST_F(InitGoogleTestTest, ListTestsFalse_f) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests=f",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false);
+}
+
+// Tests parsing --gtest_list_tests=F.
+TEST_F(InitGoogleTestTest, ListTestsFalse_F) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_list_tests=F",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ListTests(false), false);
+}
+
+// Tests parsing --gtest_output (invalid).
+TEST_F(InitGoogleTestTest, OutputEmpty) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_output",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ "--gtest_output",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), true);
+}
+
+// Tests parsing --gtest_output=xml
+TEST_F(InitGoogleTestTest, OutputXml) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_output=xml",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml"), false);
+}
+
+// Tests parsing --gtest_output=xml:file
+TEST_F(InitGoogleTestTest, OutputXmlFile) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_output=xml:file",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Output("xml:file"), false);
+}
+
+// Tests parsing --gtest_output=xml:directory/path/
+TEST_F(InitGoogleTestTest, OutputXmlDirectory) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_output=xml:directory/path/",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2,
+ Flags::Output("xml:directory/path/"), false);
+}
+
+// Tests having a --gtest_print_time flag
+TEST_F(InitGoogleTestTest, PrintTimeFlag) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false);
+}
+
+// Tests having a --gtest_print_time flag with a "true" value
+TEST_F(InitGoogleTestTest, PrintTimeTrue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(true), false);
+}
+
+// Tests having a --gtest_print_time flag with a "false" value
+TEST_F(InitGoogleTestTest, PrintTimeFalse) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false);
+}
+
+// Tests parsing --gtest_print_time=f.
+TEST_F(InitGoogleTestTest, PrintTimeFalse_f) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time=f",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false);
+}
+
+// Tests parsing --gtest_print_time=F.
+TEST_F(InitGoogleTestTest, PrintTimeFalse_F) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_print_time=F",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::PrintTime(false), false);
+}
+
+// Tests parsing --gtest_random_seed=number
+TEST_F(InitGoogleTestTest, RandomSeed) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_random_seed=1000",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::RandomSeed(1000), false);
+}
+
+// Tests parsing --gtest_repeat=number
+TEST_F(InitGoogleTestTest, Repeat) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_repeat=1000",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Repeat(1000), false);
+}
+
+// Tests having a --gtest_also_run_disabled_tests flag
+TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFlag) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_also_run_disabled_tests",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2,
+ Flags::AlsoRunDisabledTests(true), false);
+}
+
+// Tests having a --gtest_also_run_disabled_tests flag with a "true" value
+TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsTrue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_also_run_disabled_tests=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2,
+ Flags::AlsoRunDisabledTests(true), false);
+}
+
+// Tests having a --gtest_also_run_disabled_tests flag with a "false" value
+TEST_F(InitGoogleTestTest, AlsoRunDisabledTestsFalse) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_also_run_disabled_tests=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2,
+ Flags::AlsoRunDisabledTests(false), false);
+}
+
+// Tests parsing --gtest_shuffle.
+TEST_F(InitGoogleTestTest, ShuffleWithoutValue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_shuffle",
+ NULL
+};
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false);
+}
+
+// Tests parsing --gtest_shuffle=0.
+TEST_F(InitGoogleTestTest, ShuffleFalse_0) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_shuffle=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(false), false);
+}
+
+// Tests parsing a --gtest_shuffle flag that has a "true"
+// definition.
+TEST_F(InitGoogleTestTest, ShuffleTrue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_shuffle=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Shuffle(true), false);
+}
+
+// Tests parsing --gtest_stack_trace_depth=number.
+TEST_F(InitGoogleTestTest, StackTraceDepth) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_stack_trace_depth=5",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::StackTraceDepth(5), false);
+}
+
+// Tests parsing --gtest_throw_on_failure.
+TEST_F(InitGoogleTestTest, ThrowOnFailureWithoutValue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_throw_on_failure",
+ NULL
+};
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false);
+}
+
+// Tests parsing --gtest_throw_on_failure=0.
+TEST_F(InitGoogleTestTest, ThrowOnFailureFalse_0) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_throw_on_failure=0",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(false), false);
+}
+
+// Tests parsing a --gtest_throw_on_failure flag that has a "true"
+// definition.
+TEST_F(InitGoogleTestTest, ThrowOnFailureTrue) {
+ const char* argv[] = {
+ "foo.exe",
+ "--gtest_throw_on_failure=1",
+ NULL
+ };
+
+ const char* argv2[] = {
+ "foo.exe",
+ NULL
+ };
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::ThrowOnFailure(true), false);
+}
+
+#if GTEST_OS_WINDOWS
+// Tests parsing wide strings.
+TEST_F(InitGoogleTestTest, WideStrings) {
+ const wchar_t* argv[] = {
+ L"foo.exe",
+ L"--gtest_filter=Foo*",
+ L"--gtest_list_tests=1",
+ L"--gtest_break_on_failure",
+ L"--non_gtest_flag",
+ NULL
+ };
+
+ const wchar_t* argv2[] = {
+ L"foo.exe",
+ L"--non_gtest_flag",
+ NULL
+ };
+
+ Flags expected_flags;
+ expected_flags.break_on_failure = true;
+ expected_flags.filter = "Foo*";
+ expected_flags.list_tests = true;
+
+ GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false);
+}
+#endif // GTEST_OS_WINDOWS
+
+// Tests current_test_info() in UnitTest.
+class CurrentTestInfoTest : public Test {
+ protected:
+ // Tests that current_test_info() returns NULL before the first test in
+ // the test case is run.
+ static void SetUpTestCase() {
+ // There should be no tests running at this point.
+ const TestInfo* test_info =
+ UnitTest::GetInstance()->current_test_info();
+ EXPECT_TRUE(test_info == NULL)
+ << "There should be no tests running at this point.";
+ }
+
+ // Tests that current_test_info() returns NULL after the last test in
+ // the test case has run.
+ static void TearDownTestCase() {
+ const TestInfo* test_info =
+ UnitTest::GetInstance()->current_test_info();
+ EXPECT_TRUE(test_info == NULL)
+ << "There should be no tests running at this point.";
+ }
+};
+
+// Tests that current_test_info() returns TestInfo for currently running
+// test by checking the expected test name against the actual one.
+TEST_F(CurrentTestInfoTest, WorksForFirstTestInATestCase) {
+ const TestInfo* test_info =
+ UnitTest::GetInstance()->current_test_info();
+ ASSERT_TRUE(NULL != test_info)
+ << "There is a test running so we should have a valid TestInfo.";
+ EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name())
+ << "Expected the name of the currently running test case.";
+ EXPECT_STREQ("WorksForFirstTestInATestCase", test_info->name())
+ << "Expected the name of the currently running test.";
+}
+
+// Tests that current_test_info() returns TestInfo for currently running
+// test by checking the expected test name against the actual one. We
+// use this test to see that the TestInfo object actually changed from
+// the previous invocation.
+TEST_F(CurrentTestInfoTest, WorksForSecondTestInATestCase) {
+ const TestInfo* test_info =
+ UnitTest::GetInstance()->current_test_info();
+ ASSERT_TRUE(NULL != test_info)
+ << "There is a test running so we should have a valid TestInfo.";
+ EXPECT_STREQ("CurrentTestInfoTest", test_info->test_case_name())
+ << "Expected the name of the currently running test case.";
+ EXPECT_STREQ("WorksForSecondTestInATestCase", test_info->name())
+ << "Expected the name of the currently running test.";
+}
+
+} // namespace testing
+
+// These two lines test that we can define tests in a namespace that
+// has the name "testing" and is nested in another namespace.
+namespace my_namespace {
+namespace testing {
+
+// Makes sure that TEST knows to use ::testing::Test instead of
+// ::my_namespace::testing::Test.
+class Test {};
+
+// Makes sure that an assertion knows to use ::testing::Message instead of
+// ::my_namespace::testing::Message.
+class Message {};
+
+// Makes sure that an assertion knows to use
+// ::testing::AssertionResult instead of
+// ::my_namespace::testing::AssertionResult.
+class AssertionResult {};
+
+// Tests that an assertion that should succeed works as expected.
+TEST(NestedTestingNamespaceTest, Success) {
+ EXPECT_EQ(1, 1) << "This shouldn't fail.";
+}
+
+// Tests that an assertion that should fail works as expected.
+TEST(NestedTestingNamespaceTest, Failure) {
+ EXPECT_FATAL_FAILURE(FAIL() << "This failure is expected.",
+ "This failure is expected.");
+}
+
+} // namespace testing
+} // namespace my_namespace
+
+// Tests that one can call superclass SetUp and TearDown methods--
+// that is, that they are not private.
+// No tests are based on this fixture; the test "passes" if it compiles
+// successfully.
+class ProtectedFixtureMethodsTest : public Test {
+ protected:
+ virtual void SetUp() {
+ Test::SetUp();
+ }
+ virtual void TearDown() {
+ Test::TearDown();
+ }
+};
+
+// StreamingAssertionsTest tests the streaming versions of a representative
+// sample of assertions.
+TEST(StreamingAssertionsTest, Unconditional) {
+ SUCCEED() << "expected success";
+ EXPECT_NONFATAL_FAILURE(ADD_FAILURE() << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(FAIL() << "expected failure",
+ "expected failure");
+}
+
+#ifdef __BORLANDC__
+// Silences warnings: "Condition is always true", "Unreachable code"
+#pragma option push -w-ccc -w-rch
+#endif
+
+TEST(StreamingAssertionsTest, Truth) {
+ EXPECT_TRUE(true) << "unexpected failure";
+ ASSERT_TRUE(true) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_TRUE(false) << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, Truth2) {
+ EXPECT_FALSE(false) << "unexpected failure";
+ ASSERT_FALSE(false) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_FALSE(true) << "expected failure",
+ "expected failure");
+}
+
+#ifdef __BORLANDC__
+// Restores warnings after previous "#pragma option push" supressed them
+#pragma option pop
+#endif
+
+TEST(StreamingAssertionsTest, IntegerEquals) {
+ EXPECT_EQ(1, 1) << "unexpected failure";
+ ASSERT_EQ(1, 1) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_EQ(1, 2) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_EQ(1, 2) << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, IntegerLessThan) {
+ EXPECT_LT(1, 2) << "unexpected failure";
+ ASSERT_LT(1, 2) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_LT(2, 1) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_LT(2, 1) << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, StringsEqual) {
+ EXPECT_STREQ("foo", "foo") << "unexpected failure";
+ ASSERT_STREQ("foo", "foo") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STREQ("foo", "bar") << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_STREQ("foo", "bar") << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, StringsNotEqual) {
+ EXPECT_STRNE("foo", "bar") << "unexpected failure";
+ ASSERT_STRNE("foo", "bar") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("foo", "foo") << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_STRNE("foo", "foo") << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, StringsEqualIgnoringCase) {
+ EXPECT_STRCASEEQ("foo", "FOO") << "unexpected failure";
+ ASSERT_STRCASEEQ("foo", "FOO") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASEEQ("foo", "bar") << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASEEQ("foo", "bar") << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, StringNotEqualIgnoringCase) {
+ EXPECT_STRCASENE("foo", "bar") << "unexpected failure";
+ ASSERT_STRCASENE("foo", "bar") << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("foo", "FOO") << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("bar", "BAR") << "expected failure",
+ "expected failure");
+}
+
+TEST(StreamingAssertionsTest, FloatingPointEquals) {
+ EXPECT_FLOAT_EQ(1.0, 1.0) << "unexpected failure";
+ ASSERT_FLOAT_EQ(1.0, 1.0) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_FLOAT_EQ(0.0, 1.0) << "expected failure",
+ "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_FLOAT_EQ(0.0, 1.0) << "expected failure",
+ "expected failure");
+}
+
+#if GTEST_HAS_EXCEPTIONS
+
+TEST(StreamingAssertionsTest, Throw) {
+ EXPECT_THROW(ThrowAnInteger(), int) << "unexpected failure";
+ ASSERT_THROW(ThrowAnInteger(), int) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_THROW(ThrowAnInteger(), bool) <<
+ "expected failure", "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_THROW(ThrowAnInteger(), bool) <<
+ "expected failure", "expected failure");
+}
+
+TEST(StreamingAssertionsTest, NoThrow) {
+ EXPECT_NO_THROW(ThrowNothing()) << "unexpected failure";
+ ASSERT_NO_THROW(ThrowNothing()) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_NO_THROW(ThrowAnInteger()) <<
+ "expected failure", "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_NO_THROW(ThrowAnInteger()) <<
+ "expected failure", "expected failure");
+}
+
+TEST(StreamingAssertionsTest, AnyThrow) {
+ EXPECT_ANY_THROW(ThrowAnInteger()) << "unexpected failure";
+ ASSERT_ANY_THROW(ThrowAnInteger()) << "unexpected failure";
+ EXPECT_NONFATAL_FAILURE(EXPECT_ANY_THROW(ThrowNothing()) <<
+ "expected failure", "expected failure");
+ EXPECT_FATAL_FAILURE(ASSERT_ANY_THROW(ThrowNothing()) <<
+ "expected failure", "expected failure");
+}
+
+#endif // GTEST_HAS_EXCEPTIONS
+
+// Tests that Google Test correctly decides whether to use colors in the output.
+
+TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsYes) {
+ GTEST_FLAG(color) = "yes";
+
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+
+ SetEnv("TERM", "dumb"); // TERM doesn't support colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+}
+
+TEST(ColoredOutputTest, UsesColorsWhenGTestColorFlagIsAliasOfYes) {
+ SetEnv("TERM", "dumb"); // TERM doesn't support colors.
+
+ GTEST_FLAG(color) = "True";
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+
+ GTEST_FLAG(color) = "t";
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+
+ GTEST_FLAG(color) = "1";
+ EXPECT_TRUE(ShouldUseColor(false)); // Stdout is not a TTY.
+}
+
+TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsNo) {
+ GTEST_FLAG(color) = "no";
+
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+ EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY.
+
+ SetEnv("TERM", "dumb"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+ EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY.
+}
+
+TEST(ColoredOutputTest, UsesNoColorWhenGTestColorFlagIsInvalid) {
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+
+ GTEST_FLAG(color) = "F";
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ GTEST_FLAG(color) = "0";
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ GTEST_FLAG(color) = "unknown";
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+}
+
+TEST(ColoredOutputTest, UsesColorsWhenStdoutIsTty) {
+ GTEST_FLAG(color) = "auto";
+
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+ EXPECT_FALSE(ShouldUseColor(false)); // Stdout is not a TTY.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+}
+
+TEST(ColoredOutputTest, UsesColorsWhenTermSupportsColors) {
+ GTEST_FLAG(color) = "auto";
+
+#if GTEST_OS_WINDOWS
+ // On Windows, we ignore the TERM variable as it's usually not set.
+
+ SetEnv("TERM", "dumb");
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "");
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm");
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+#else
+ // On non-Windows platforms, we rely on TERM to determine if the
+ // terminal supports colors.
+
+ SetEnv("TERM", "dumb"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "emacs"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "vt100"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm-mono"); // TERM doesn't support colors.
+ EXPECT_FALSE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "xterm-color"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+
+ SetEnv("TERM", "linux"); // TERM supports colors.
+ EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY.
+#endif // GTEST_OS_WINDOWS
+}
+
+// Verifies that StaticAssertTypeEq works in a namespace scope.
+
+static bool dummy1 = StaticAssertTypeEq<bool, bool>();
+static bool dummy2 = StaticAssertTypeEq<const int, const int>();
+
+// Verifies that StaticAssertTypeEq works in a class.
+
+template <typename T>
+class StaticAssertTypeEqTestHelper {
+ public:
+ StaticAssertTypeEqTestHelper() { StaticAssertTypeEq<bool, T>(); }
+};
+
+TEST(StaticAssertTypeEqTest, WorksInClass) {
+ StaticAssertTypeEqTestHelper<bool>();
+}
+
+// Verifies that StaticAssertTypeEq works inside a function.
+
+typedef int IntAlias;
+
+TEST(StaticAssertTypeEqTest, CompilesForEqualTypes) {
+ StaticAssertTypeEq<int, IntAlias>();
+ StaticAssertTypeEq<int*, IntAlias*>();
+}
+
+TEST(GetCurrentOsStackTraceExceptTopTest, ReturnsTheStackTrace) {
+ testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();
+
+ // We don't have a stack walker in Google Test yet.
+ EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 0).c_str());
+ EXPECT_STREQ("", GetCurrentOsStackTraceExceptTop(unit_test, 1).c_str());
+}
+
+TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsNoFailure) {
+ EXPECT_FALSE(HasNonfatalFailure());
+}
+
+static void FailFatally() { FAIL(); }
+
+TEST(HasNonfatalFailureTest, ReturnsFalseWhenThereIsOnlyFatalFailure) {
+ FailFatally();
+ const bool has_nonfatal_failure = HasNonfatalFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_FALSE(has_nonfatal_failure);
+}
+
+TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) {
+ ADD_FAILURE();
+ const bool has_nonfatal_failure = HasNonfatalFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_nonfatal_failure);
+}
+
+TEST(HasNonfatalFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) {
+ FailFatally();
+ ADD_FAILURE();
+ const bool has_nonfatal_failure = HasNonfatalFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_nonfatal_failure);
+}
+
+// A wrapper for calling HasNonfatalFailure outside of a test body.
+static bool HasNonfatalFailureHelper() {
+ return testing::Test::HasNonfatalFailure();
+}
+
+TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody) {
+ EXPECT_FALSE(HasNonfatalFailureHelper());
+}
+
+TEST(HasNonfatalFailureTest, WorksOutsideOfTestBody2) {
+ ADD_FAILURE();
+ const bool has_nonfatal_failure = HasNonfatalFailureHelper();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_nonfatal_failure);
+}
+
+TEST(HasFailureTest, ReturnsFalseWhenThereIsNoFailure) {
+ EXPECT_FALSE(HasFailure());
+}
+
+TEST(HasFailureTest, ReturnsTrueWhenThereIsFatalFailure) {
+ FailFatally();
+ const bool has_failure = HasFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_failure);
+}
+
+TEST(HasFailureTest, ReturnsTrueWhenThereIsNonfatalFailure) {
+ ADD_FAILURE();
+ const bool has_failure = HasFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_failure);
+}
+
+TEST(HasFailureTest, ReturnsTrueWhenThereAreFatalAndNonfatalFailures) {
+ FailFatally();
+ ADD_FAILURE();
+ const bool has_failure = HasFailure();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_failure);
+}
+
+// A wrapper for calling HasFailure outside of a test body.
+static bool HasFailureHelper() { return testing::Test::HasFailure(); }
+
+TEST(HasFailureTest, WorksOutsideOfTestBody) {
+ EXPECT_FALSE(HasFailureHelper());
+}
+
+TEST(HasFailureTest, WorksOutsideOfTestBody2) {
+ ADD_FAILURE();
+ const bool has_failure = HasFailureHelper();
+ ClearCurrentTestPartResults();
+ EXPECT_TRUE(has_failure);
+}
+
+class TestListener : public EmptyTestEventListener {
+ public:
+ TestListener() : on_start_counter_(NULL), is_destroyed_(NULL) {}
+ TestListener(int* on_start_counter, bool* is_destroyed)
+ : on_start_counter_(on_start_counter),
+ is_destroyed_(is_destroyed) {}
+
+ virtual ~TestListener() {
+ if (is_destroyed_)
+ *is_destroyed_ = true;
+ }
+
+ protected:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {
+ if (on_start_counter_ != NULL)
+ (*on_start_counter_)++;
+ }
+
+ private:
+ int* on_start_counter_;
+ bool* is_destroyed_;
+};
+
+// Tests the constructor.
+TEST(TestEventListenersTest, ConstructionWorks) {
+ TestEventListeners listeners;
+
+ EXPECT_TRUE(TestEventListenersAccessor::GetRepeater(&listeners) != NULL);
+ EXPECT_TRUE(listeners.default_result_printer() == NULL);
+ EXPECT_TRUE(listeners.default_xml_generator() == NULL);
+}
+
+// Tests that the TestEventListeners destructor deletes all the listeners it
+// owns.
+TEST(TestEventListenersTest, DestructionWorks) {
+ bool default_result_printer_is_destroyed = false;
+ bool default_xml_printer_is_destroyed = false;
+ bool extra_listener_is_destroyed = false;
+ TestListener* default_result_printer = new TestListener(
+ NULL, &default_result_printer_is_destroyed);
+ TestListener* default_xml_printer = new TestListener(
+ NULL, &default_xml_printer_is_destroyed);
+ TestListener* extra_listener = new TestListener(
+ NULL, &extra_listener_is_destroyed);
+
+ {
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultResultPrinter(&listeners,
+ default_result_printer);
+ TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners,
+ default_xml_printer);
+ listeners.Append(extra_listener);
+ }
+ EXPECT_TRUE(default_result_printer_is_destroyed);
+ EXPECT_TRUE(default_xml_printer_is_destroyed);
+ EXPECT_TRUE(extra_listener_is_destroyed);
+}
+
+// Tests that a listener Append'ed to a TestEventListeners list starts
+// receiving events.
+TEST(TestEventListenersTest, Append) {
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+ {
+ TestEventListeners listeners;
+ listeners.Append(listener);
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(1, on_start_counter);
+ }
+ EXPECT_TRUE(is_destroyed);
+}
+
+// Tests that listeners receive events in the order they were appended to
+// the list, except for *End requests, which must be received in the reverse
+// order.
+class SequenceTestingListener : public EmptyTestEventListener {
+ public:
+ SequenceTestingListener(std::vector<String>* vector, const char* id)
+ : vector_(vector), id_(id) {}
+
+ protected:
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {
+ vector_->push_back(GetEventDescription("OnTestProgramStart"));
+ }
+
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {
+ vector_->push_back(GetEventDescription("OnTestProgramEnd"));
+ }
+
+ virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {
+ vector_->push_back(GetEventDescription("OnTestIterationStart"));
+ }
+
+ virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
+ int /*iteration*/) {
+ vector_->push_back(GetEventDescription("OnTestIterationEnd"));
+ }
+
+ private:
+ String GetEventDescription(const char* method) {
+ Message message;
+ message << id_ << "." << method;
+ return message.GetString();
+ }
+
+ std::vector<String>* vector_;
+ const char* const id_;
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SequenceTestingListener);
+};
+
+TEST(EventListenerTest, AppendKeepsOrder) {
+ std::vector<String> vec;
+ TestEventListeners listeners;
+ listeners.Append(new SequenceTestingListener(&vec, "1st"));
+ listeners.Append(new SequenceTestingListener(&vec, "2nd"));
+ listeners.Append(new SequenceTestingListener(&vec, "3rd"));
+
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ ASSERT_EQ(3U, vec.size());
+ EXPECT_STREQ("1st.OnTestProgramStart", vec[0].c_str());
+ EXPECT_STREQ("2nd.OnTestProgramStart", vec[1].c_str());
+ EXPECT_STREQ("3rd.OnTestProgramStart", vec[2].c_str());
+
+ vec.clear();
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramEnd(
+ *UnitTest::GetInstance());
+ ASSERT_EQ(3U, vec.size());
+ EXPECT_STREQ("3rd.OnTestProgramEnd", vec[0].c_str());
+ EXPECT_STREQ("2nd.OnTestProgramEnd", vec[1].c_str());
+ EXPECT_STREQ("1st.OnTestProgramEnd", vec[2].c_str());
+
+ vec.clear();
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationStart(
+ *UnitTest::GetInstance(), 0);
+ ASSERT_EQ(3U, vec.size());
+ EXPECT_STREQ("1st.OnTestIterationStart", vec[0].c_str());
+ EXPECT_STREQ("2nd.OnTestIterationStart", vec[1].c_str());
+ EXPECT_STREQ("3rd.OnTestIterationStart", vec[2].c_str());
+
+ vec.clear();
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestIterationEnd(
+ *UnitTest::GetInstance(), 0);
+ ASSERT_EQ(3U, vec.size());
+ EXPECT_STREQ("3rd.OnTestIterationEnd", vec[0].c_str());
+ EXPECT_STREQ("2nd.OnTestIterationEnd", vec[1].c_str());
+ EXPECT_STREQ("1st.OnTestIterationEnd", vec[2].c_str());
+}
+
+// Tests that a listener removed from a TestEventListeners list stops receiving
+// events and is not deleted when the list is destroyed.
+TEST(TestEventListenersTest, Release) {
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ // Although Append passes the ownership of this object to the list,
+ // the following calls release it, and we need to delete it before the
+ // test ends.
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+ {
+ TestEventListeners listeners;
+ listeners.Append(listener);
+ EXPECT_EQ(listener, listeners.Release(listener));
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_TRUE(listeners.Release(listener) == NULL);
+ }
+ EXPECT_EQ(0, on_start_counter);
+ EXPECT_FALSE(is_destroyed);
+ delete listener;
+}
+
+// Tests that no events are forwarded when event forwarding is disabled.
+TEST(EventListenerTest, SuppressEventForwarding) {
+ int on_start_counter = 0;
+ TestListener* listener = new TestListener(&on_start_counter, NULL);
+
+ TestEventListeners listeners;
+ listeners.Append(listener);
+ ASSERT_TRUE(TestEventListenersAccessor::EventForwardingEnabled(listeners));
+ TestEventListenersAccessor::SuppressEventForwarding(&listeners);
+ ASSERT_FALSE(TestEventListenersAccessor::EventForwardingEnabled(listeners));
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(0, on_start_counter);
+}
+
+// Tests that events generated by Google Test are not forwarded in
+// death test subprocesses.
+TEST(EventListenerDeathTest, EventsNotForwardedInDeathTestSubprecesses) {
+ EXPECT_DEATH_IF_SUPPORTED({
+ GTEST_CHECK_(TestEventListenersAccessor::EventForwardingEnabled(
+ *GetUnitTestImpl()->listeners())) << "expected failure";},
+ "expected failure");
+}
+
+// Tests that a listener installed via SetDefaultResultPrinter() starts
+// receiving events and is returned via default_result_printer() and that
+// the previous default_result_printer is removed from the list and deleted.
+TEST(EventListenerTest, default_result_printer) {
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener);
+
+ EXPECT_EQ(listener, listeners.default_result_printer());
+
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+
+ EXPECT_EQ(1, on_start_counter);
+
+ // Replacing default_result_printer with something else should remove it
+ // from the list and destroy it.
+ TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, NULL);
+
+ EXPECT_TRUE(listeners.default_result_printer() == NULL);
+ EXPECT_TRUE(is_destroyed);
+
+ // After broadcasting an event the counter is still the same, indicating
+ // the listener is not in the list anymore.
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(1, on_start_counter);
+}
+
+// Tests that the default_result_printer listener stops receiving events
+// when removed via Release and that is not owned by the list anymore.
+TEST(EventListenerTest, RemovingDefaultResultPrinterWorks) {
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ // Although Append passes the ownership of this object to the list,
+ // the following calls release it, and we need to delete it before the
+ // test ends.
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+ {
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultResultPrinter(&listeners, listener);
+
+ EXPECT_EQ(listener, listeners.Release(listener));
+ EXPECT_TRUE(listeners.default_result_printer() == NULL);
+ EXPECT_FALSE(is_destroyed);
+
+ // Broadcasting events now should not affect default_result_printer.
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(0, on_start_counter);
+ }
+ // Destroying the list should not affect the listener now, too.
+ EXPECT_FALSE(is_destroyed);
+ delete listener;
+}
+
+// Tests that a listener installed via SetDefaultXmlGenerator() starts
+// receiving events and is returned via default_xml_generator() and that
+// the previous default_xml_generator is removed from the list and deleted.
+TEST(EventListenerTest, default_xml_generator) {
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener);
+
+ EXPECT_EQ(listener, listeners.default_xml_generator());
+
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+
+ EXPECT_EQ(1, on_start_counter);
+
+ // Replacing default_xml_generator with something else should remove it
+ // from the list and destroy it.
+ TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, NULL);
+
+ EXPECT_TRUE(listeners.default_xml_generator() == NULL);
+ EXPECT_TRUE(is_destroyed);
+
+ // After broadcasting an event the counter is still the same, indicating
+ // the listener is not in the list anymore.
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(1, on_start_counter);
+}
+
+// Tests that the default_xml_generator listener stops receiving events
+// when removed via Release and that is not owned by the list anymore.
+TEST(EventListenerTest, RemovingDefaultXmlGeneratorWorks) {
+ int on_start_counter = 0;
+ bool is_destroyed = false;
+ // Although Append passes the ownership of this object to the list,
+ // the following calls release it, and we need to delete it before the
+ // test ends.
+ TestListener* listener = new TestListener(&on_start_counter, &is_destroyed);
+ {
+ TestEventListeners listeners;
+ TestEventListenersAccessor::SetDefaultXmlGenerator(&listeners, listener);
+
+ EXPECT_EQ(listener, listeners.Release(listener));
+ EXPECT_TRUE(listeners.default_xml_generator() == NULL);
+ EXPECT_FALSE(is_destroyed);
+
+ // Broadcasting events now should not affect default_xml_generator.
+ TestEventListenersAccessor::GetRepeater(&listeners)->OnTestProgramStart(
+ *UnitTest::GetInstance());
+ EXPECT_EQ(0, on_start_counter);
+ }
+ // Destroying the list should not affect the listener now, too.
+ EXPECT_FALSE(is_destroyed);
+ delete listener;
+}
+
+// Sanity tests to ensure that the alternative, verbose spellings of
+// some of the macros work. We don't test them thoroughly as that
+// would be quite involved. Since their implementations are
+// straightforward, and they are rarely used, we'll just rely on the
+// users to tell us when they are broken.
+GTEST_TEST(AlternativeNameTest, Works) { // GTEST_TEST is the same as TEST.
+ GTEST_SUCCEED() << "OK"; // GTEST_SUCCEED is the same as SUCCEED.
+
+ // GTEST_FAIL is the same as FAIL.
+ EXPECT_FATAL_FAILURE(GTEST_FAIL() << "An expected failure",
+ "An expected failure");
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_xml_outfile1_test_.cc b/Source/ThirdParty/gtest/test/gtest_xml_outfile1_test_.cc
new file mode 100644
index 000000000..664baad2a
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_xml_outfile1_test_.cc
@@ -0,0 +1,49 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray@gmail.com (Keith Ray)
+//
+// gtest_xml_outfile1_test_ writes some xml via TestProperty used by
+// gtest_xml_outfiles_test.py
+
+#include <gtest/gtest.h>
+
+class PropertyOne : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ RecordProperty("SetUpProp", 1);
+ }
+ virtual void TearDown() {
+ RecordProperty("TearDownProp", 1);
+ }
+};
+
+TEST_F(PropertyOne, TestSomeProperties) {
+ RecordProperty("TestSomeProperty", 1);
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_xml_outfile2_test_.cc b/Source/ThirdParty/gtest/test/gtest_xml_outfile2_test_.cc
new file mode 100644
index 000000000..3411a3d38
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_xml_outfile2_test_.cc
@@ -0,0 +1,49 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: keith.ray@gmail.com (Keith Ray)
+//
+// gtest_xml_outfile2_test_ writes some xml via TestProperty used by
+// gtest_xml_outfiles_test.py
+
+#include <gtest/gtest.h>
+
+class PropertyTwo : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ RecordProperty("SetUpProp", 2);
+ }
+ virtual void TearDown() {
+ RecordProperty("TearDownProp", 2);
+ }
+};
+
+TEST_F(PropertyTwo, TestSomeProperties) {
+ RecordProperty("TestSomeProperty", 2);
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_xml_outfiles_test.py b/Source/ThirdParty/gtest/test/gtest_xml_outfiles_test.py
new file mode 100755
index 000000000..0fe947f08
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_xml_outfiles_test.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for the gtest_xml_output module."""
+
+__author__ = "keith.ray@gmail.com (Keith Ray)"
+
+import os
+from xml.dom import minidom, Node
+
+import gtest_test_utils
+import gtest_xml_test_utils
+
+
+GTEST_OUTPUT_SUBDIR = "xml_outfiles"
+GTEST_OUTPUT_1_TEST = "gtest_xml_outfile1_test_"
+GTEST_OUTPUT_2_TEST = "gtest_xml_outfile2_test_"
+
+EXPECTED_XML_1 = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" name="AllTests">
+ <testsuite name="PropertyOne" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="TestSomeProperties" status="run" time="*" classname="PropertyOne" SetUpProp="1" TestSomeProperty="1" TearDownProp="1" />
+ </testsuite>
+</testsuites>
+"""
+
+EXPECTED_XML_2 = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="1" failures="0" disabled="0" errors="0" time="*" name="AllTests">
+ <testsuite name="PropertyTwo" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="TestSomeProperties" status="run" time="*" classname="PropertyTwo" SetUpProp="2" TestSomeProperty="2" TearDownProp="2" />
+ </testsuite>
+</testsuites>
+"""
+
+
+class GTestXMLOutFilesTest(gtest_xml_test_utils.GTestXMLTestCase):
+ """Unit test for Google Test's XML output functionality."""
+
+ def setUp(self):
+ # We want the trailing '/' that the last "" provides in os.path.join, for
+ # telling Google Test to create an output directory instead of a single file
+ # for xml output.
+ self.output_dir_ = os.path.join(gtest_test_utils.GetTempDir(),
+ GTEST_OUTPUT_SUBDIR, "")
+ self.DeleteFilesAndDir()
+
+ def tearDown(self):
+ self.DeleteFilesAndDir()
+
+ def DeleteFilesAndDir(self):
+ try:
+ os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_1_TEST + ".xml"))
+ except os.error:
+ pass
+ try:
+ os.remove(os.path.join(self.output_dir_, GTEST_OUTPUT_2_TEST + ".xml"))
+ except os.error:
+ pass
+ try:
+ os.rmdir(self.output_dir_)
+ except os.error:
+ pass
+
+ def testOutfile1(self):
+ self._TestOutFile(GTEST_OUTPUT_1_TEST, EXPECTED_XML_1)
+
+ def testOutfile2(self):
+ self._TestOutFile(GTEST_OUTPUT_2_TEST, EXPECTED_XML_2)
+
+ def _TestOutFile(self, test_name, expected_xml):
+ gtest_prog_path = gtest_test_utils.GetTestExecutablePath(test_name)
+ command = [gtest_prog_path, "--gtest_output=xml:%s" % self.output_dir_]
+ p = gtest_test_utils.Subprocess(command,
+ working_dir=gtest_test_utils.GetTempDir())
+ self.assert_(p.exited)
+ self.assertEquals(0, p.exit_code)
+
+ # TODO(wan@google.com): libtool causes the built test binary to be
+ # named lt-gtest_xml_outfiles_test_ instead of
+ # gtest_xml_outfiles_test_. To account for this possibillity, we
+ # allow both names in the following code. We should remove this
+ # hack when Chandler Carruth's libtool replacement tool is ready.
+ output_file_name1 = test_name + ".xml"
+ output_file1 = os.path.join(self.output_dir_, output_file_name1)
+ output_file_name2 = 'lt-' + output_file_name1
+ output_file2 = os.path.join(self.output_dir_, output_file_name2)
+ self.assert_(os.path.isfile(output_file1) or os.path.isfile(output_file2),
+ output_file1)
+
+ expected = minidom.parseString(expected_xml)
+ if os.path.isfile(output_file1):
+ actual = minidom.parse(output_file1)
+ else:
+ actual = minidom.parse(output_file2)
+ self.NormalizeXml(actual.documentElement)
+ self.AssertEquivalentNodes(expected.documentElement,
+ actual.documentElement)
+ expected.unlink()
+ actual.unlink()
+
+
+if __name__ == "__main__":
+ os.environ["GTEST_STACK_TRACE_DEPTH"] = "0"
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_xml_output_unittest.py b/Source/ThirdParty/gtest/test/gtest_xml_output_unittest.py
new file mode 100755
index 000000000..6d44929ca
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_xml_output_unittest.py
@@ -0,0 +1,224 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test for the gtest_xml_output module"""
+
+__author__ = 'eefacm@gmail.com (Sean Mcafee)'
+
+import errno
+import os
+import sys
+from xml.dom import minidom, Node
+
+import gtest_test_utils
+import gtest_xml_test_utils
+
+
+GTEST_OUTPUT_FLAG = "--gtest_output"
+GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml"
+GTEST_PROGRAM_NAME = "gtest_xml_output_unittest_"
+
+SUPPORTS_STACK_TRACES = False
+
+if SUPPORTS_STACK_TRACES:
+ STACK_TRACE_TEMPLATE = "\nStack trace:\n*"
+else:
+ STACK_TRACE_TEMPLATE = ""
+
+EXPECTED_NON_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="15" failures="4" disabled="2" errors="0" time="*" name="AllTests">
+ <testsuite name="SuccessfulTest" tests="1" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="Succeeds" status="run" time="*" classname="SuccessfulTest"/>
+ </testsuite>
+ <testsuite name="FailedTest" tests="1" failures="1" disabled="0" errors="0" time="*">
+ <testcase name="Fails" status="run" time="*" classname="FailedTest">
+ <failure message="Value of: 2&#x0A;Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Value of: 2
+Expected: 1%(stack)s]]></failure>
+ </testcase>
+ </testsuite>
+ <testsuite name="MixedResultTest" tests="3" failures="1" disabled="1" errors="0" time="*">
+ <testcase name="Succeeds" status="run" time="*" classname="MixedResultTest"/>
+ <testcase name="Fails" status="run" time="*" classname="MixedResultTest">
+ <failure message="Value of: 2&#x0A;Expected: 1" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Value of: 2
+Expected: 1%(stack)s]]></failure>
+ <failure message="Value of: 3&#x0A;Expected: 2" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Value of: 3
+Expected: 2%(stack)s]]></failure>
+ </testcase>
+ <testcase name="DISABLED_test" status="notrun" time="*" classname="MixedResultTest"/>
+ </testsuite>
+ <testsuite name="XmlQuotingTest" tests="1" failures="1" disabled="0" errors="0" time="*">
+ <testcase name="OutputsCData" status="run" time="*" classname="XmlQuotingTest">
+ <failure message="Failed&#x0A;XML output: &lt;?xml encoding=&quot;utf-8&quot;&gt;&lt;top&gt;&lt;![CDATA[cdata text]]&gt;&lt;/top&gt;" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Failed
+XML output: <?xml encoding="utf-8"><top><![CDATA[cdata text]]>]]&gt;<![CDATA[</top>%(stack)s]]></failure>
+ </testcase>
+ </testsuite>
+ <testsuite name="InvalidCharactersTest" tests="1" failures="1" disabled="0" errors="0" time="*">
+ <testcase name="InvalidCharactersInMessage" status="run" time="*" classname="InvalidCharactersTest">
+ <failure message="Failed&#x0A;Invalid characters in brackets []" type=""><![CDATA[gtest_xml_output_unittest_.cc:*
+Failed
+Invalid characters in brackets []%(stack)s]]></failure>
+ </testcase>
+ </testsuite>
+ <testsuite name="DisabledTest" tests="1" failures="0" disabled="1" errors="0" time="*">
+ <testcase name="DISABLED_test_not_run" status="notrun" time="*" classname="DisabledTest"/>
+ </testsuite>
+ <testsuite name="PropertyRecordingTest" tests="4" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="OneProperty" status="run" time="*" classname="PropertyRecordingTest" key_1="1"/>
+ <testcase name="IntValuedProperty" status="run" time="*" classname="PropertyRecordingTest" key_int="1"/>
+ <testcase name="ThreeProperties" status="run" time="*" classname="PropertyRecordingTest" key_1="1" key_2="2" key_3="3"/>
+ <testcase name="TwoValuesForOneKeyUsesLastValue" status="run" time="*" classname="PropertyRecordingTest" key_1="2"/>
+ </testsuite>
+ <testsuite name="NoFixtureTest" tests="3" failures="0" disabled="0" errors="0" time="*">
+ <testcase name="RecordProperty" status="run" time="*" classname="NoFixtureTest" key="1"/>
+ <testcase name="ExternalUtilityThatCallsRecordIntValuedProperty" status="run" time="*" classname="NoFixtureTest" key_for_utility_int="1"/>
+ <testcase name="ExternalUtilityThatCallsRecordStringValuedProperty" status="run" time="*" classname="NoFixtureTest" key_for_utility_string="1"/>
+ </testsuite>
+</testsuites>""" % {'stack': STACK_TRACE_TEMPLATE}
+
+
+EXPECTED_EMPTY_XML = """<?xml version="1.0" encoding="UTF-8"?>
+<testsuites tests="0" failures="0" disabled="0" errors="0" time="*" name="AllTests">
+</testsuites>"""
+
+
+class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase):
+ """
+ Unit test for Google Test's XML output functionality.
+ """
+
+ def testNonEmptyXmlOutput(self):
+ """
+ Runs a test program that generates a non-empty XML output, and
+ tests that the XML output is expected.
+ """
+ self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_NON_EMPTY_XML, 1)
+
+ def testEmptyXmlOutput(self):
+ """
+ Runs a test program that generates an empty XML output, and
+ tests that the XML output is expected.
+ """
+
+ self._TestXmlOutput("gtest_no_test_unittest",
+ EXPECTED_EMPTY_XML, 0)
+
+ def testDefaultOutputFile(self):
+ """
+ Confirms that Google Test produces an XML output file with the expected
+ default name if no name is explicitly specified.
+ """
+ output_file = os.path.join(gtest_test_utils.GetTempDir(),
+ GTEST_DEFAULT_OUTPUT_FILE)
+ gtest_prog_path = gtest_test_utils.GetTestExecutablePath(
+ "gtest_no_test_unittest")
+ try:
+ os.remove(output_file)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+
+ p = gtest_test_utils.Subprocess(
+ [gtest_prog_path, "%s=xml" % GTEST_OUTPUT_FLAG],
+ working_dir=gtest_test_utils.GetTempDir())
+ self.assert_(p.exited)
+ self.assertEquals(0, p.exit_code)
+ self.assert_(os.path.isfile(output_file))
+
+ def testSuppressedXmlOutput(self):
+ """
+ Tests that no XML file is generated if the default XML listener is
+ shut down before RUN_ALL_TESTS is invoked.
+ """
+
+ xml_path = os.path.join(gtest_test_utils.GetTempDir(),
+ GTEST_PROGRAM_NAME + "out.xml")
+ if os.path.isfile(xml_path):
+ os.remove(xml_path)
+
+ gtest_prog_path = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME)
+
+ command = [gtest_prog_path,
+ "%s=xml:%s" % (GTEST_OUTPUT_FLAG, xml_path),
+ "--shut_down_xml"]
+ p = gtest_test_utils.Subprocess(command)
+ if p.terminated_by_signal:
+ self.assert_(False,
+ "%s was killed by signal %d" % (gtest_prog_name, p.signal))
+ else:
+ self.assert_(p.exited)
+ self.assertEquals(1, p.exit_code,
+ "'%s' exited with code %s, which doesn't match "
+ "the expected exit code %s."
+ % (command, p.exit_code, 1))
+
+ self.assert_(not os.path.isfile(xml_path))
+
+
+ def _TestXmlOutput(self, gtest_prog_name, expected_xml, expected_exit_code):
+ """
+ Asserts that the XML document generated by running the program
+ gtest_prog_name matches expected_xml, a string containing another
+ XML document. Furthermore, the program's exit code must be
+ expected_exit_code.
+ """
+ xml_path = os.path.join(gtest_test_utils.GetTempDir(),
+ gtest_prog_name + "out.xml")
+ gtest_prog_path = gtest_test_utils.GetTestExecutablePath(gtest_prog_name)
+
+ command = [gtest_prog_path, "%s=xml:%s" % (GTEST_OUTPUT_FLAG, xml_path)]
+ p = gtest_test_utils.Subprocess(command)
+ if p.terminated_by_signal:
+ self.assert_(False,
+ "%s was killed by signal %d" % (gtest_prog_name, p.signal))
+ else:
+ self.assert_(p.exited)
+ self.assertEquals(expected_exit_code, p.exit_code,
+ "'%s' exited with code %s, which doesn't match "
+ "the expected exit code %s."
+ % (command, p.exit_code, expected_exit_code))
+
+ expected = minidom.parseString(expected_xml)
+ actual = minidom.parse(xml_path)
+ self.NormalizeXml(actual.documentElement)
+ self.AssertEquivalentNodes(expected.documentElement,
+ actual.documentElement)
+ expected.unlink()
+ actual .unlink()
+
+
+
+if __name__ == '__main__':
+ os.environ['GTEST_STACK_TRACE_DEPTH'] = '1'
+ gtest_test_utils.Main()
diff --git a/Source/ThirdParty/gtest/test/gtest_xml_output_unittest_.cc b/Source/ThirdParty/gtest/test/gtest_xml_output_unittest_.cc
new file mode 100644
index 000000000..fc07ef46b
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_xml_output_unittest_.cc
@@ -0,0 +1,145 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: eefacm@gmail.com (Sean Mcafee)
+
+// Unit test for Google Test XML output.
+//
+// A user can specify XML output in a Google Test program to run via
+// either the GTEST_OUTPUT environment variable or the --gtest_output
+// flag. This is used for testing such functionality.
+//
+// This program will be invoked from a Python unit test. Don't run it
+// directly.
+
+#include <gtest/gtest.h>
+
+using ::testing::InitGoogleTest;
+using ::testing::TestEventListeners;
+using ::testing::UnitTest;
+
+class SuccessfulTest : public testing::Test {
+};
+
+TEST_F(SuccessfulTest, Succeeds) {
+ SUCCEED() << "This is a success.";
+ ASSERT_EQ(1, 1);
+}
+
+class FailedTest : public testing::Test {
+};
+
+TEST_F(FailedTest, Fails) {
+ ASSERT_EQ(1, 2);
+}
+
+class DisabledTest : public testing::Test {
+};
+
+TEST_F(DisabledTest, DISABLED_test_not_run) {
+ FAIL() << "Unexpected failure: Disabled test should not be run";
+}
+
+TEST(MixedResultTest, Succeeds) {
+ EXPECT_EQ(1, 1);
+ ASSERT_EQ(1, 1);
+}
+
+TEST(MixedResultTest, Fails) {
+ EXPECT_EQ(1, 2);
+ ASSERT_EQ(2, 3);
+}
+
+TEST(MixedResultTest, DISABLED_test) {
+ FAIL() << "Unexpected failure: Disabled test should not be run";
+}
+
+TEST(XmlQuotingTest, OutputsCData) {
+ FAIL() << "XML output: "
+ "<?xml encoding=\"utf-8\"><top><![CDATA[cdata text]]></top>";
+}
+
+// Helps to test that invalid characters produced by test code do not make
+// it into the XML file.
+TEST(InvalidCharactersTest, InvalidCharactersInMessage) {
+ FAIL() << "Invalid characters in brackets [\x1\x2]";
+}
+
+class PropertyRecordingTest : public testing::Test {
+};
+
+TEST_F(PropertyRecordingTest, OneProperty) {
+ RecordProperty("key_1", "1");
+}
+
+TEST_F(PropertyRecordingTest, IntValuedProperty) {
+ RecordProperty("key_int", 1);
+}
+
+TEST_F(PropertyRecordingTest, ThreeProperties) {
+ RecordProperty("key_1", "1");
+ RecordProperty("key_2", "2");
+ RecordProperty("key_3", "3");
+}
+
+TEST_F(PropertyRecordingTest, TwoValuesForOneKeyUsesLastValue) {
+ RecordProperty("key_1", "1");
+ RecordProperty("key_1", "2");
+}
+
+TEST(NoFixtureTest, RecordProperty) {
+ RecordProperty("key", "1");
+}
+
+void ExternalUtilityThatCallsRecordProperty(const char* key, int value) {
+ testing::Test::RecordProperty(key, value);
+}
+
+void ExternalUtilityThatCallsRecordProperty(const char* key,
+ const char* value) {
+ testing::Test::RecordProperty(key, value);
+}
+
+TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) {
+ ExternalUtilityThatCallsRecordProperty("key_for_utility_int", 1);
+}
+
+TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) {
+ ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1");
+}
+
+int main(int argc, char** argv) {
+ InitGoogleTest(&argc, argv);
+
+ if (argc > 1 && strcmp(argv[1], "--shut_down_xml") == 0) {
+ TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_xml_generator());
+ }
+ return RUN_ALL_TESTS();
+}
diff --git a/Source/ThirdParty/gtest/test/gtest_xml_test_utils.py b/Source/ThirdParty/gtest/test/gtest_xml_test_utils.py
new file mode 100755
index 000000000..c83c3b7ea
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/gtest_xml_test_utils.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit test utilities for gtest_xml_output"""
+
+__author__ = 'eefacm@gmail.com (Sean Mcafee)'
+
+import re
+from xml.dom import minidom, Node
+
+import gtest_test_utils
+
+
+GTEST_OUTPUT_FLAG = "--gtest_output"
+GTEST_DEFAULT_OUTPUT_FILE = "test_detail.xml"
+
+class GTestXMLTestCase(gtest_test_utils.TestCase):
+ """
+ Base class for tests of Google Test's XML output functionality.
+ """
+
+
+ def AssertEquivalentNodes(self, expected_node, actual_node):
+ """
+ Asserts that actual_node (a DOM node object) is equivalent to
+ expected_node (another DOM node object), in that either both of
+ them are CDATA nodes and have the same value, or both are DOM
+ elements and actual_node meets all of the following conditions:
+
+ * It has the same tag name as expected_node.
+ * It has the same set of attributes as expected_node, each with
+ the same value as the corresponding attribute of expected_node.
+ An exception is any attribute named "time", which needs only be
+ convertible to a floating-point number.
+ * It has an equivalent set of child nodes (including elements and
+ CDATA sections) as expected_node. Note that we ignore the
+ order of the children as they are not guaranteed to be in any
+ particular order.
+ """
+
+ if expected_node.nodeType == Node.CDATA_SECTION_NODE:
+ self.assertEquals(Node.CDATA_SECTION_NODE, actual_node.nodeType)
+ self.assertEquals(expected_node.nodeValue, actual_node.nodeValue)
+ return
+
+ self.assertEquals(Node.ELEMENT_NODE, actual_node.nodeType)
+ self.assertEquals(Node.ELEMENT_NODE, expected_node.nodeType)
+ self.assertEquals(expected_node.tagName, actual_node.tagName)
+
+ expected_attributes = expected_node.attributes
+ actual_attributes = actual_node .attributes
+ self.assertEquals(
+ expected_attributes.length, actual_attributes.length,
+ "attribute numbers differ in element " + actual_node.tagName)
+ for i in range(expected_attributes.length):
+ expected_attr = expected_attributes.item(i)
+ actual_attr = actual_attributes.get(expected_attr.name)
+ self.assert_(
+ actual_attr is not None,
+ "expected attribute %s not found in element %s" %
+ (expected_attr.name, actual_node.tagName))
+ self.assertEquals(expected_attr.value, actual_attr.value,
+ " values of attribute %s in element %s differ" %
+ (expected_attr.name, actual_node.tagName))
+
+ expected_children = self._GetChildren(expected_node)
+ actual_children = self._GetChildren(actual_node)
+ self.assertEquals(
+ len(expected_children), len(actual_children),
+ "number of child elements differ in element " + actual_node.tagName)
+ for child_id, child in expected_children.iteritems():
+ self.assert_(child_id in actual_children,
+ '<%s> is not in <%s> (in element %s)' %
+ (child_id, actual_children, actual_node.tagName))
+ self.AssertEquivalentNodes(child, actual_children[child_id])
+
+ identifying_attribute = {
+ "testsuites": "name",
+ "testsuite": "name",
+ "testcase": "name",
+ "failure": "message",
+ }
+
+ def _GetChildren(self, element):
+ """
+ Fetches all of the child nodes of element, a DOM Element object.
+ Returns them as the values of a dictionary keyed by the IDs of the
+ children. For <testsuites>, <testsuite> and <testcase> elements, the ID
+ is the value of their "name" attribute; for <failure> elements, it is
+ the value of the "message" attribute; CDATA sections and non-whitespace
+ text nodes are concatenated into a single CDATA section with ID
+ "detail". An exception is raised if any element other than the above
+ four is encountered, if two child elements with the same identifying
+ attributes are encountered, or if any other type of node is encountered.
+ """
+
+ children = {}
+ for child in element.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ self.assert_(child.tagName in self.identifying_attribute,
+ "Encountered unknown element <%s>" % child.tagName)
+ childID = child.getAttribute(self.identifying_attribute[child.tagName])
+ self.assert_(childID not in children)
+ children[childID] = child
+ elif child.nodeType in [Node.TEXT_NODE, Node.CDATA_SECTION_NODE]:
+ if "detail" not in children:
+ if (child.nodeType == Node.CDATA_SECTION_NODE or
+ not child.nodeValue.isspace()):
+ children["detail"] = child.ownerDocument.createCDATASection(
+ child.nodeValue)
+ else:
+ children["detail"].nodeValue += child.nodeValue
+ else:
+ self.fail("Encountered unexpected node type %d" % child.nodeType)
+ return children
+
+ def NormalizeXml(self, element):
+ """
+ Normalizes Google Test's XML output to eliminate references to transient
+ information that may change from run to run.
+
+ * The "time" attribute of <testsuites>, <testsuite> and <testcase>
+ elements is replaced with a single asterisk, if it contains
+ only digit characters.
+ * The line number reported in the first line of the "message"
+ attribute of <failure> elements is replaced with a single asterisk.
+ * The directory names in file paths are removed.
+ * The stack traces are removed.
+ """
+
+ if element.tagName in ("testsuites", "testsuite", "testcase"):
+ time = element.getAttributeNode("time")
+ time.value = re.sub(r"^\d+(\.\d+)?$", "*", time.value)
+ elif element.tagName == "failure":
+ for child in element.childNodes:
+ if child.nodeType == Node.CDATA_SECTION_NODE:
+ # Removes the source line number.
+ cdata = re.sub(r"^.*[/\\](.*:)\d+\n", "\\1*\n", child.nodeValue)
+ # Removes the actual stack trace.
+ child.nodeValue = re.sub(r"\nStack trace:\n(.|\n)*",
+ "", cdata)
+ for child in element.childNodes:
+ if child.nodeType == Node.ELEMENT_NODE:
+ self.NormalizeXml(child)
diff --git a/Source/ThirdParty/gtest/test/production.cc b/Source/ThirdParty/gtest/test/production.cc
new file mode 100644
index 000000000..8b8a40b44
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/production.cc
@@ -0,0 +1,36 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This is part of the unit test for include/gtest/gtest_prod.h.
+
+#include "production.h"
+
+PrivateCode::PrivateCode() : x_(0) {}
diff --git a/Source/ThirdParty/gtest/test/production.h b/Source/ThirdParty/gtest/test/production.h
new file mode 100644
index 000000000..8f16fffa2
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/production.h
@@ -0,0 +1,55 @@
+// Copyright 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: wan@google.com (Zhanyong Wan)
+//
+// This is part of the unit test for include/gtest/gtest_prod.h.
+
+#ifndef GTEST_TEST_PRODUCTION_H_
+#define GTEST_TEST_PRODUCTION_H_
+
+#include <gtest/gtest_prod.h>
+
+class PrivateCode {
+ public:
+ // Declares a friend test that does not use a fixture.
+ FRIEND_TEST(PrivateCodeTest, CanAccessPrivateMembers);
+
+ // Declares a friend test that uses a fixture.
+ FRIEND_TEST(PrivateCodeFixtureTest, CanAccessPrivateMembers);
+
+ PrivateCode();
+
+ int x() const { return x_; }
+ private:
+ void set_x(int an_x) { x_ = an_x; }
+ int x_;
+};
+
+#endif // GTEST_TEST_PRODUCTION_H_
diff --git a/Source/ThirdParty/gtest/test/run_tests_util.py b/Source/ThirdParty/gtest/test/run_tests_util.py
new file mode 100755
index 000000000..9e57931eb
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/run_tests_util.py
@@ -0,0 +1,466 @@
+# Copyright 2008 Google Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Provides facilities for running SCons-built Google Test/Mock tests."""
+
+
+import optparse
+import os
+import re
+import sets
+import sys
+
+try:
+ # subrocess module is a preferable way to invoke subprocesses but it may
+ # not be available on MacOS X 10.4.
+ # Suppresses the 'Import not at the top of the file' lint complaint.
+ # pylint: disable-msg=C6204
+ import subprocess
+except ImportError:
+ subprocess = None
+
+HELP_MSG = """Runs the specified tests for %(proj)s.
+
+SYNOPSIS
+ run_tests.py [OPTION]... [BUILD_DIR]... [TEST]...
+
+DESCRIPTION
+ Runs the specified tests (either binary or Python), and prints a
+ summary of the results. BUILD_DIRS will be used to search for the
+ binaries. If no TESTs are specified, all binary tests found in
+ BUILD_DIRs and all Python tests found in the directory test/ (in the
+ %(proj)s root) are run.
+
+ TEST is a name of either a binary or a Python test. A binary test is
+ an executable file named *_test or *_unittest (with the .exe
+ extension on Windows) A Python test is a script named *_test.py or
+ *_unittest.py.
+
+OPTIONS
+ -h, --help
+ Print this help message.
+ -c CONFIGURATIONS
+ Specify build directories via build configurations.
+ CONFIGURATIONS is either a comma-separated list of build
+ configurations or 'all'. Each configuration is equivalent to
+ adding 'scons/build/<configuration>/%(proj)s/scons' to BUILD_DIRs.
+ Specifying -c=all is equivalent to providing all directories
+ listed in KNOWN BUILD DIRECTORIES section below.
+ -a
+ Equivalent to -c=all
+ -b
+ Equivalent to -c=all with the exception that the script will not
+ fail if some of the KNOWN BUILD DIRECTORIES do not exists; the
+ script will simply not run the tests there. 'b' stands for
+ 'built directories'.
+
+RETURN VALUE
+ Returns 0 if all tests are successful; otherwise returns 1.
+
+EXAMPLES
+ run_tests.py
+ Runs all tests for the default build configuration.
+ run_tests.py -a
+ Runs all tests with binaries in KNOWN BUILD DIRECTORIES.
+ run_tests.py -b
+ Runs all tests in KNOWN BUILD DIRECTORIES that have been
+ built.
+ run_tests.py foo/
+ Runs all tests in the foo/ directory and all Python tests in
+ the directory test. The Python tests are instructed to look
+ for binaries in foo/.
+ run_tests.py bar_test.exe test/baz_test.exe foo/ bar/
+ Runs foo/bar_test.exe, bar/bar_test.exe, foo/baz_test.exe, and
+ bar/baz_test.exe.
+ run_tests.py foo bar test/foo_test.py
+ Runs test/foo_test.py twice instructing it to look for its
+ test binaries in the directories foo and bar,
+ correspondingly.
+
+KNOWN BUILD DIRECTORIES
+ run_tests.py knows about directories where the SCons build script
+ deposits its products. These are the directories where run_tests.py
+ will be looking for its binaries. Currently, %(proj)s's SConstruct file
+ defines them as follows (the default build directory is the first one
+ listed in each group):
+ On Windows:
+ <%(proj)s root>/scons/build/win-dbg8/%(proj)s/scons/
+ <%(proj)s root>/scons/build/win-opt8/%(proj)s/scons/
+ On Mac:
+ <%(proj)s root>/scons/build/mac-dbg/%(proj)s/scons/
+ <%(proj)s root>/scons/build/mac-opt/%(proj)s/scons/
+ On other platforms:
+ <%(proj)s root>/scons/build/dbg/%(proj)s/scons/
+ <%(proj)s root>/scons/build/opt/%(proj)s/scons/"""
+
+IS_WINDOWS = os.name == 'nt'
+IS_MAC = os.name == 'posix' and os.uname()[0] == 'Darwin'
+IS_CYGWIN = os.name == 'posix' and 'CYGWIN' in os.uname()[0]
+
+# Definition of CONFIGS must match that of the build directory names in the
+# SConstruct script. The first list item is the default build configuration.
+if IS_WINDOWS:
+ CONFIGS = ('win-dbg8', 'win-opt8')
+elif IS_MAC:
+ CONFIGS = ('mac-dbg', 'mac-opt')
+else:
+ CONFIGS = ('dbg', 'opt')
+
+if IS_WINDOWS or IS_CYGWIN:
+ PYTHON_TEST_REGEX = re.compile(r'_(unit)?test\.py$', re.IGNORECASE)
+ BINARY_TEST_REGEX = re.compile(r'_(unit)?test(\.exe)?$', re.IGNORECASE)
+ BINARY_TEST_SEARCH_REGEX = re.compile(r'_(unit)?test\.exe$', re.IGNORECASE)
+else:
+ PYTHON_TEST_REGEX = re.compile(r'_(unit)?test\.py$')
+ BINARY_TEST_REGEX = re.compile(r'_(unit)?test$')
+ BINARY_TEST_SEARCH_REGEX = BINARY_TEST_REGEX
+
+
+def _GetGtestBuildDir(injected_os, script_dir, config):
+ """Calculates path to the Google Test SCons build directory."""
+
+ return injected_os.path.normpath(injected_os.path.join(script_dir,
+ 'scons/build',
+ config,
+ 'gtest/scons'))
+
+
+def _GetConfigFromBuildDir(build_dir):
+ """Extracts the configuration name from the build directory."""
+
+ # We don't want to depend on build_dir containing the correct path
+ # separators.
+ m = re.match(r'.*[\\/]([^\\/]+)[\\/][^\\/]+[\\/]scons[\\/]?$', build_dir)
+ if m:
+ return m.group(1)
+ else:
+ print >>sys.stderr, ('%s is an invalid build directory that does not '
+ 'correspond to any configuration.' % (build_dir,))
+ return ''
+
+
+# All paths in this script are either absolute or relative to the current
+# working directory, unless otherwise specified.
+class TestRunner(object):
+ """Provides facilities for running Python and binary tests for Google Test."""
+
+ def __init__(self,
+ script_dir,
+ build_dir_var_name='GTEST_BUILD_DIR',
+ injected_os=os,
+ injected_subprocess=subprocess,
+ injected_build_dir_finder=_GetGtestBuildDir):
+ """Initializes a TestRunner instance.
+
+ Args:
+ script_dir: File path to the calling script.
+ build_dir_var_name: Name of the env variable used to pass the
+ the build directory path to the invoked
+ tests.
+ injected_os: standard os module or a mock/stub for
+ testing.
+ injected_subprocess: standard subprocess module or a mock/stub
+ for testing
+ injected_build_dir_finder: function that determines the path to
+ the build directory.
+ """
+
+ self.os = injected_os
+ self.subprocess = injected_subprocess
+ self.build_dir_finder = injected_build_dir_finder
+ self.build_dir_var_name = build_dir_var_name
+ self.script_dir = script_dir
+
+ def _GetBuildDirForConfig(self, config):
+ """Returns the build directory for a given configuration."""
+
+ return self.build_dir_finder(self.os, self.script_dir, config)
+
+ def _Run(self, args):
+ """Runs the executable with given args (args[0] is the executable name).
+
+ Args:
+ args: Command line arguments for the process.
+
+ Returns:
+ Process's exit code if it exits normally, or -signal if the process is
+ killed by a signal.
+ """
+
+ if self.subprocess:
+ return self.subprocess.Popen(args).wait()
+ else:
+ return self.os.spawnv(self.os.P_WAIT, args[0], args)
+
+ def _RunBinaryTest(self, test):
+ """Runs the binary test given its path.
+
+ Args:
+ test: Path to the test binary.
+
+ Returns:
+ Process's exit code if it exits normally, or -signal if the process is
+ killed by a signal.
+ """
+
+ return self._Run([test])
+
+ def _RunPythonTest(self, test, build_dir):
+ """Runs the Python test script with the specified build directory.
+
+ Args:
+ test: Path to the test's Python script.
+ build_dir: Path to the directory where the test binary is to be found.
+
+ Returns:
+ Process's exit code if it exits normally, or -signal if the process is
+ killed by a signal.
+ """
+
+ old_build_dir = self.os.environ.get(self.build_dir_var_name)
+
+ try:
+ self.os.environ[self.build_dir_var_name] = build_dir
+
+ # If this script is run on a Windows machine that has no association
+ # between the .py extension and a python interpreter, simply passing
+ # the script name into subprocess.Popen/os.spawn will not work.
+ print 'Running %s . . .' % (test,)
+ return self._Run([sys.executable, test])
+
+ finally:
+ if old_build_dir is None:
+ del self.os.environ[self.build_dir_var_name]
+ else:
+ self.os.environ[self.build_dir_var_name] = old_build_dir
+
+ def _FindFilesByRegex(self, directory, regex):
+ """Returns files in a directory whose names match a regular expression.
+
+ Args:
+ directory: Path to the directory to search for files.
+ regex: Regular expression to filter file names.
+
+ Returns:
+ The list of the paths to the files in the directory.
+ """
+
+ return [self.os.path.join(directory, file_name)
+ for file_name in self.os.listdir(directory)
+ if re.search(regex, file_name)]
+
+ # TODO(vladl@google.com): Implement parsing of scons/SConscript to run all
+ # tests defined there when no tests are specified.
+ # TODO(vladl@google.com): Update the docstring after the code is changed to
+ # try to test all builds defined in scons/SConscript.
+ def GetTestsToRun(self,
+ args,
+ named_configurations,
+ built_configurations,
+ available_configurations=CONFIGS,
+ python_tests_to_skip=None):
+ """Determines what tests should be run.
+
+ Args:
+ args: The list of non-option arguments from the command line.
+ named_configurations: The list of configurations specified via -c or -a.
+ built_configurations: True if -b has been specified.
+ available_configurations: a list of configurations available on the
+ current platform, injectable for testing.
+ python_tests_to_skip: a collection of (configuration, python test name)s
+ that need to be skipped.
+
+ Returns:
+ A tuple with 2 elements: the list of Python tests to run and the list of
+ binary tests to run.
+ """
+
+ if named_configurations == 'all':
+ named_configurations = ','.join(available_configurations)
+
+ normalized_args = [self.os.path.normpath(arg) for arg in args]
+
+ # A final list of build directories which will be searched for the test
+ # binaries. First, add directories specified directly on the command
+ # line.
+ build_dirs = filter(self.os.path.isdir, normalized_args)
+
+ # Adds build directories specified via their build configurations using
+ # the -c or -a options.
+ if named_configurations:
+ build_dirs += [self._GetBuildDirForConfig(config)
+ for config in named_configurations.split(',')]
+
+ # Adds KNOWN BUILD DIRECTORIES if -b is specified.
+ if built_configurations:
+ build_dirs += [self._GetBuildDirForConfig(config)
+ for config in available_configurations
+ if self.os.path.isdir(self._GetBuildDirForConfig(config))]
+
+ # If no directories were specified either via -a, -b, -c, or directly, use
+ # the default configuration.
+ elif not build_dirs:
+ build_dirs = [self._GetBuildDirForConfig(available_configurations[0])]
+
+ # Makes sure there are no duplications.
+ build_dirs = sets.Set(build_dirs)
+
+ errors_found = False
+ listed_python_tests = [] # All Python tests listed on the command line.
+ listed_binary_tests = [] # All binary tests listed on the command line.
+
+ test_dir = self.os.path.normpath(self.os.path.join(self.script_dir, 'test'))
+
+ # Sifts through non-directory arguments fishing for any Python or binary
+ # tests and detecting errors.
+ for argument in sets.Set(normalized_args) - build_dirs:
+ if re.search(PYTHON_TEST_REGEX, argument):
+ python_path = self.os.path.join(test_dir,
+ self.os.path.basename(argument))
+ if self.os.path.isfile(python_path):
+ listed_python_tests.append(python_path)
+ else:
+ sys.stderr.write('Unable to find Python test %s' % argument)
+ errors_found = True
+ elif re.search(BINARY_TEST_REGEX, argument):
+ # This script also accepts binary test names prefixed with test/ for
+ # the convenience of typing them (can use path completions in the
+ # shell). Strips test/ prefix from the binary test names.
+ listed_binary_tests.append(self.os.path.basename(argument))
+ else:
+ sys.stderr.write('%s is neither test nor build directory' % argument)
+ errors_found = True
+
+ if errors_found:
+ return None
+
+ user_has_listed_tests = listed_python_tests or listed_binary_tests
+
+ if user_has_listed_tests:
+ selected_python_tests = listed_python_tests
+ else:
+ selected_python_tests = self._FindFilesByRegex(test_dir,
+ PYTHON_TEST_REGEX)
+
+ # TODO(vladl@google.com): skip unbuilt Python tests when -b is specified.
+ python_test_pairs = []
+ for directory in build_dirs:
+ for test in selected_python_tests:
+ config = _GetConfigFromBuildDir(directory)
+ file_name = os.path.basename(test)
+ if python_tests_to_skip and (config, file_name) in python_tests_to_skip:
+ print ('NOTE: %s is skipped for configuration %s, as it does not '
+ 'work there.' % (file_name, config))
+ else:
+ python_test_pairs.append((directory, test))
+
+ binary_test_pairs = []
+ for directory in build_dirs:
+ if user_has_listed_tests:
+ binary_test_pairs.extend(
+ [(directory, self.os.path.join(directory, test))
+ for test in listed_binary_tests])
+ else:
+ tests = self._FindFilesByRegex(directory, BINARY_TEST_SEARCH_REGEX)
+ binary_test_pairs.extend([(directory, test) for test in tests])
+
+ return (python_test_pairs, binary_test_pairs)
+
+ def RunTests(self, python_tests, binary_tests):
+ """Runs Python and binary tests and reports results to the standard output.
+
+ Args:
+ python_tests: List of Python tests to run in the form of tuples
+ (build directory, Python test script).
+ binary_tests: List of binary tests to run in the form of tuples
+ (build directory, binary file).
+
+ Returns:
+ The exit code the program should pass into sys.exit().
+ """
+
+ if python_tests or binary_tests:
+ results = []
+ for directory, test in python_tests:
+ results.append((directory,
+ test,
+ self._RunPythonTest(test, directory) == 0))
+ for directory, test in binary_tests:
+ results.append((directory,
+ self.os.path.basename(test),
+ self._RunBinaryTest(test) == 0))
+
+ failed = [(directory, test)
+ for (directory, test, success) in results
+ if not success]
+ print
+ print '%d tests run.' % len(results)
+ if failed:
+ print 'The following %d tests failed:' % len(failed)
+ for (directory, test) in failed:
+ print '%s in %s' % (test, directory)
+ return 1
+ else:
+ print 'All tests passed!'
+ else: # No tests defined
+ print 'Nothing to test - no tests specified!'
+
+ return 0
+
+
+def ParseArgs(project_name, argv=None, help_callback=None):
+ """Parses the options run_tests.py uses."""
+
+ # Suppresses lint warning on unused arguments. These arguments are
+ # required by optparse, even though they are unused.
+ # pylint: disable-msg=W0613
+ def PrintHelp(option, opt, value, parser):
+ print HELP_MSG % {'proj': project_name}
+ sys.exit(1)
+
+ parser = optparse.OptionParser()
+ parser.add_option('-c',
+ action='store',
+ dest='configurations',
+ default=None)
+ parser.add_option('-a',
+ action='store_const',
+ dest='configurations',
+ default=None,
+ const='all')
+ parser.add_option('-b',
+ action='store_const',
+ dest='built_configurations',
+ default=False,
+ const=True)
+ # Replaces the built-in help with ours.
+ parser.remove_option('-h')
+ parser.add_option('-h', '--help',
+ action='callback',
+ callback=help_callback or PrintHelp)
+ return parser.parse_args(argv)
diff --git a/Source/ThirdParty/gtest/test/run_tests_util_test.py b/Source/ThirdParty/gtest/test/run_tests_util_test.py
new file mode 100755
index 000000000..9c55726fd
--- /dev/null
+++ b/Source/ThirdParty/gtest/test/run_tests_util_test.py
@@ -0,0 +1,676 @@
+#!/usr/bin/env python
+#
+# Copyright 2009 Google Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests for run_tests_util.py test runner script."""
+
+__author__ = 'vladl@google.com (Vlad Losev)'
+
+import os
+import re
+import sets
+import unittest
+
+import run_tests_util
+
+
+GTEST_DBG_DIR = 'scons/build/dbg/gtest/scons'
+GTEST_OPT_DIR = 'scons/build/opt/gtest/scons'
+GTEST_OTHER_DIR = 'scons/build/other/gtest/scons'
+
+
+def AddExeExtension(path):
+ """Appends .exe to the path on Windows or Cygwin."""
+
+ if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN:
+ return path + '.exe'
+ else:
+ return path
+
+
+class FakePath(object):
+ """A fake os.path module for testing."""
+
+ def __init__(self, current_dir=os.getcwd(), known_paths=None):
+ self.current_dir = current_dir
+ self.tree = {}
+ self.path_separator = os.sep
+
+ # known_paths contains either absolute or relative paths. Relative paths
+ # are absolutized with self.current_dir.
+ if known_paths:
+ self._AddPaths(known_paths)
+
+ def _AddPath(self, path):
+ ends_with_slash = path.endswith('/')
+ path = self.abspath(path)
+ if ends_with_slash:
+ path += self.path_separator
+ name_list = path.split(self.path_separator)
+ tree = self.tree
+ for name in name_list[:-1]:
+ if not name:
+ continue
+ if name in tree:
+ tree = tree[name]
+ else:
+ tree[name] = {}
+ tree = tree[name]
+
+ name = name_list[-1]
+ if name:
+ if name in tree:
+ assert tree[name] == 1
+ else:
+ tree[name] = 1
+
+ def _AddPaths(self, paths):
+ for path in paths:
+ self._AddPath(path)
+
+ def PathElement(self, path):
+ """Returns an internal representation of directory tree entry for path."""
+ tree = self.tree
+ name_list = self.abspath(path).split(self.path_separator)
+ for name in name_list:
+ if not name:
+ continue
+ tree = tree.get(name, None)
+ if tree is None:
+ break
+
+ return tree
+
+ # Silences pylint warning about using standard names.
+ # pylint: disable-msg=C6409
+ def normpath(self, path):
+ return os.path.normpath(path)
+
+ def abspath(self, path):
+ return self.normpath(os.path.join(self.current_dir, path))
+
+ def isfile(self, path):
+ return self.PathElement(self.abspath(path)) == 1
+
+ def isdir(self, path):
+ return type(self.PathElement(self.abspath(path))) == type(dict())
+
+ def basename(self, path):
+ return os.path.basename(path)
+
+ def dirname(self, path):
+ return os.path.dirname(path)
+
+ def join(self, *kargs):
+ return os.path.join(*kargs)
+
+
+class FakeOs(object):
+ """A fake os module for testing."""
+ P_WAIT = os.P_WAIT
+
+ def __init__(self, fake_path_module):
+ self.path = fake_path_module
+
+ # Some methods/attributes are delegated to the real os module.
+ self.environ = os.environ
+
+ # pylint: disable-msg=C6409
+ def listdir(self, path):
+ assert self.path.isdir(path)
+ return self.path.PathElement(path).iterkeys()
+
+ def spawnv(self, wait, executable, *kargs):
+ assert wait == FakeOs.P_WAIT
+ return self.spawn_impl(executable, kargs)
+
+
+class GetTestsToRunTest(unittest.TestCase):
+ """Exercises TestRunner.GetTestsToRun."""
+
+ def NormalizeGetTestsToRunResults(self, results):
+ """Normalizes path data returned from GetTestsToRun for comparison."""
+
+ def NormalizePythonTestPair(pair):
+ """Normalizes path data in the (directory, python_script) pair."""
+
+ return (os.path.normpath(pair[0]), os.path.normpath(pair[1]))
+
+ def NormalizeBinaryTestPair(pair):
+ """Normalizes path data in the (directory, binary_executable) pair."""
+
+ directory, executable = map(os.path.normpath, pair)
+
+ # On Windows and Cygwin, the test file names have the .exe extension, but
+ # they can be invoked either by name or by name+extension. Our test must
+ # accommodate both situations.
+ if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN:
+ executable = re.sub(r'\.exe$', '', executable)
+ return (directory, executable)
+
+ python_tests = sets.Set(map(NormalizePythonTestPair, results[0]))
+ binary_tests = sets.Set(map(NormalizeBinaryTestPair, results[1]))
+ return (python_tests, binary_tests)
+
+ def AssertResultsEqual(self, results, expected):
+ """Asserts results returned by GetTestsToRun equal to expected results."""
+
+ self.assertEqual(self.NormalizeGetTestsToRunResults(results),
+ self.NormalizeGetTestsToRunResults(expected),
+ 'Incorrect set of tests returned:\n%s\nexpected:\n%s' %
+ (results, expected))
+
+ def setUp(self):
+ self.fake_os = FakeOs(FakePath(
+ current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)),
+ known_paths=[AddExeExtension(GTEST_DBG_DIR + '/gtest_unittest'),
+ AddExeExtension(GTEST_OPT_DIR + '/gtest_unittest'),
+ 'test/gtest_color_test.py']))
+ self.fake_configurations = ['dbg', 'opt']
+ self.test_runner = run_tests_util.TestRunner(script_dir='.',
+ injected_os=self.fake_os,
+ injected_subprocess=None)
+
+ def testBinaryTestsOnly(self):
+ """Exercises GetTestsToRun with parameters designating binary tests only."""
+
+ # A default build.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_unittest'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]))
+
+ # An explicitly specified directory.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [GTEST_DBG_DIR, 'gtest_unittest'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]))
+
+ # A particular configuration.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_unittest'],
+ 'other',
+ False,
+ available_configurations=self.fake_configurations),
+ ([],
+ [(GTEST_OTHER_DIR, GTEST_OTHER_DIR + '/gtest_unittest')]))
+
+ # All available configurations
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_unittest'],
+ 'all',
+ False,
+ available_configurations=self.fake_configurations),
+ ([],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest'),
+ (GTEST_OPT_DIR, GTEST_OPT_DIR + '/gtest_unittest')]))
+
+ # All built configurations (unbuilt don't cause failure).
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_unittest'],
+ '',
+ True,
+ available_configurations=self.fake_configurations + ['unbuilt']),
+ ([],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest'),
+ (GTEST_OPT_DIR, GTEST_OPT_DIR + '/gtest_unittest')]))
+
+ # A combination of an explicit directory and a configuration.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [GTEST_DBG_DIR, 'gtest_unittest'],
+ 'opt',
+ False,
+ available_configurations=self.fake_configurations),
+ ([],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest'),
+ (GTEST_OPT_DIR, GTEST_OPT_DIR + '/gtest_unittest')]))
+
+ # Same test specified in an explicit directory and via a configuration.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [GTEST_DBG_DIR, 'gtest_unittest'],
+ 'dbg',
+ False,
+ available_configurations=self.fake_configurations),
+ ([],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]))
+
+ # All built configurations + explicit directory + explicit configuration.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [GTEST_DBG_DIR, 'gtest_unittest'],
+ 'opt',
+ True,
+ available_configurations=self.fake_configurations),
+ ([],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest'),
+ (GTEST_OPT_DIR, GTEST_OPT_DIR + '/gtest_unittest')]))
+
+ def testPythonTestsOnly(self):
+ """Exercises GetTestsToRun with parameters designating Python tests only."""
+
+ # A default build.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_color_test.py'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ # An explicitly specified directory.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [GTEST_DBG_DIR, 'test/gtest_color_test.py'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ # A particular configuration.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_color_test.py'],
+ 'other',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_OTHER_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ # All available configurations
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['test/gtest_color_test.py'],
+ 'all',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py'),
+ (GTEST_OPT_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ # All built configurations (unbuilt don't cause failure).
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_color_test.py'],
+ '',
+ True,
+ available_configurations=self.fake_configurations + ['unbuilt']),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py'),
+ (GTEST_OPT_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ # A combination of an explicit directory and a configuration.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [GTEST_DBG_DIR, 'gtest_color_test.py'],
+ 'opt',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py'),
+ (GTEST_OPT_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ # Same test specified in an explicit directory and via a configuration.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [GTEST_DBG_DIR, 'gtest_color_test.py'],
+ 'dbg',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ # All built configurations + explicit directory + explicit configuration.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [GTEST_DBG_DIR, 'gtest_color_test.py'],
+ 'opt',
+ True,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py'),
+ (GTEST_OPT_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ def testCombinationOfBinaryAndPythonTests(self):
+ """Exercises GetTestsToRun with mixed binary/Python tests."""
+
+ # Use only default configuration for this test.
+
+ # Neither binary nor Python tests are specified so find all.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]))
+
+ # Specifying both binary and Python tests.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_unittest', 'gtest_color_test.py'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]))
+
+ # Specifying binary tests suppresses Python tests.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_unittest'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]))
+
+ # Specifying Python tests suppresses binary tests.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_color_test.py'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([(GTEST_DBG_DIR, 'test/gtest_color_test.py')],
+ []))
+
+ def testIgnoresNonTestFiles(self):
+ """Verifies that GetTestsToRun ignores non-test files in the filesystem."""
+
+ self.fake_os = FakeOs(FakePath(
+ current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)),
+ known_paths=[AddExeExtension(GTEST_DBG_DIR + '/gtest_nontest'),
+ 'test/']))
+ self.test_runner = run_tests_util.TestRunner(script_dir='.',
+ injected_os=self.fake_os,
+ injected_subprocess=None)
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [],
+ '',
+ True,
+ available_configurations=self.fake_configurations),
+ ([], []))
+
+ def testWorksFromDifferentDir(self):
+ """Exercises GetTestsToRun from a directory different from run_test.py's."""
+
+ # Here we simulate an test script in directory /d/ called from the
+ # directory /a/b/c/.
+ self.fake_os = FakeOs(FakePath(
+ current_dir=os.path.abspath('/a/b/c'),
+ known_paths=[
+ '/a/b/c/',
+ AddExeExtension('/d/' + GTEST_DBG_DIR + '/gtest_unittest'),
+ AddExeExtension('/d/' + GTEST_OPT_DIR + '/gtest_unittest'),
+ '/d/test/gtest_color_test.py']))
+ self.fake_configurations = ['dbg', 'opt']
+ self.test_runner = run_tests_util.TestRunner(script_dir='/d/',
+ injected_os=self.fake_os,
+ injected_subprocess=None)
+ # A binary test.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_unittest'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([],
+ [('/d/' + GTEST_DBG_DIR, '/d/' + GTEST_DBG_DIR + '/gtest_unittest')]))
+
+ # A Python test.
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ ['gtest_color_test.py'],
+ '',
+ False,
+ available_configurations=self.fake_configurations),
+ ([('/d/' + GTEST_DBG_DIR, '/d/test/gtest_color_test.py')], []))
+
+ def testNonTestBinary(self):
+ """Exercises GetTestsToRun with a non-test parameter."""
+
+ self.assert_(
+ not self.test_runner.GetTestsToRun(
+ ['gtest_unittest_not_really'],
+ '',
+ False,
+ available_configurations=self.fake_configurations))
+
+ def testNonExistingPythonTest(self):
+ """Exercises GetTestsToRun with a non-existent Python test parameter."""
+
+ self.assert_(
+ not self.test_runner.GetTestsToRun(
+ ['nonexistent_test.py'],
+ '',
+ False,
+ available_configurations=self.fake_configurations))
+
+ if run_tests_util.IS_WINDOWS or run_tests_util.IS_CYGWIN:
+
+ def testDoesNotPickNonExeFilesOnWindows(self):
+ """Verifies that GetTestsToRun does not find _test files on Windows."""
+
+ self.fake_os = FakeOs(FakePath(
+ current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)),
+ known_paths=['/d/' + GTEST_DBG_DIR + '/gtest_test', 'test/']))
+ self.test_runner = run_tests_util.TestRunner(script_dir='.',
+ injected_os=self.fake_os,
+ injected_subprocess=None)
+ self.AssertResultsEqual(
+ self.test_runner.GetTestsToRun(
+ [],
+ '',
+ True,
+ available_configurations=self.fake_configurations),
+ ([], []))
+
+
+class RunTestsTest(unittest.TestCase):
+ """Exercises TestRunner.RunTests."""
+
+ def SpawnSuccess(self, unused_executable, unused_argv):
+ """Fakes test success by returning 0 as an exit code."""
+
+ self.num_spawn_calls += 1
+ return 0
+
+ def SpawnFailure(self, unused_executable, unused_argv):
+ """Fakes test success by returning 1 as an exit code."""
+
+ self.num_spawn_calls += 1
+ return 1
+
+ def setUp(self):
+ self.fake_os = FakeOs(FakePath(
+ current_dir=os.path.abspath(os.path.dirname(run_tests_util.__file__)),
+ known_paths=[
+ AddExeExtension(GTEST_DBG_DIR + '/gtest_unittest'),
+ AddExeExtension(GTEST_OPT_DIR + '/gtest_unittest'),
+ 'test/gtest_color_test.py']))
+ self.fake_configurations = ['dbg', 'opt']
+ self.test_runner = run_tests_util.TestRunner(
+ script_dir=os.path.dirname(__file__) or '.',
+ injected_os=self.fake_os,
+ injected_subprocess=None)
+ self.num_spawn_calls = 0 # A number of calls to spawn.
+
+ def testRunPythonTestSuccess(self):
+ """Exercises RunTests to handle a Python test success."""
+
+ self.fake_os.spawn_impl = self.SpawnSuccess
+ self.assertEqual(
+ self.test_runner.RunTests(
+ [(GTEST_DBG_DIR, 'test/gtest_color_test.py')],
+ []),
+ 0)
+ self.assertEqual(self.num_spawn_calls, 1)
+
+ def testRunBinaryTestSuccess(self):
+ """Exercises RunTests to handle a binary test success."""
+
+ self.fake_os.spawn_impl = self.SpawnSuccess
+ self.assertEqual(
+ self.test_runner.RunTests(
+ [],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]),
+ 0)
+ self.assertEqual(self.num_spawn_calls, 1)
+
+ def testRunPythonTestFauilure(self):
+ """Exercises RunTests to handle a Python test failure."""
+
+ self.fake_os.spawn_impl = self.SpawnFailure
+ self.assertEqual(
+ self.test_runner.RunTests(
+ [(GTEST_DBG_DIR, 'test/gtest_color_test.py')],
+ []),
+ 1)
+ self.assertEqual(self.num_spawn_calls, 1)
+
+ def testRunBinaryTestFailure(self):
+ """Exercises RunTests to handle a binary test failure."""
+
+ self.fake_os.spawn_impl = self.SpawnFailure
+ self.assertEqual(
+ self.test_runner.RunTests(
+ [],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]),
+ 1)
+ self.assertEqual(self.num_spawn_calls, 1)
+
+ def testCombinedTestSuccess(self):
+ """Exercises RunTests to handle a success of both Python and binary test."""
+
+ self.fake_os.spawn_impl = self.SpawnSuccess
+ self.assertEqual(
+ self.test_runner.RunTests(
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]),
+ 0)
+ self.assertEqual(self.num_spawn_calls, 2)
+
+ def testCombinedTestSuccessAndFailure(self):
+ """Exercises RunTests to handle a success of both Python and binary test."""
+
+ def SpawnImpl(executable, argv):
+ self.num_spawn_calls += 1
+ # Simulates failure of a Python test and success of a binary test.
+ if '.py' in executable or '.py' in argv[0]:
+ return 1
+ else:
+ return 0
+
+ self.fake_os.spawn_impl = SpawnImpl
+ self.assertEqual(
+ self.test_runner.RunTests(
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')],
+ [(GTEST_DBG_DIR, GTEST_DBG_DIR + '/gtest_unittest')]),
+ 0)
+ self.assertEqual(self.num_spawn_calls, 2)
+
+
+class ParseArgsTest(unittest.TestCase):
+ """Exercises ParseArgs."""
+
+ def testNoOptions(self):
+ options, args = run_tests_util.ParseArgs('gtest', argv=['script.py'])
+ self.assertEqual(args, ['script.py'])
+ self.assert_(options.configurations is None)
+ self.assertFalse(options.built_configurations)
+
+ def testOptionC(self):
+ options, args = run_tests_util.ParseArgs(
+ 'gtest', argv=['script.py', '-c', 'dbg'])
+ self.assertEqual(args, ['script.py'])
+ self.assertEqual(options.configurations, 'dbg')
+ self.assertFalse(options.built_configurations)
+
+ def testOptionA(self):
+ options, args = run_tests_util.ParseArgs('gtest', argv=['script.py', '-a'])
+ self.assertEqual(args, ['script.py'])
+ self.assertEqual(options.configurations, 'all')
+ self.assertFalse(options.built_configurations)
+
+ def testOptionB(self):
+ options, args = run_tests_util.ParseArgs('gtest', argv=['script.py', '-b'])
+ self.assertEqual(args, ['script.py'])
+ self.assert_(options.configurations is None)
+ self.assertTrue(options.built_configurations)
+
+ def testOptionCAndOptionB(self):
+ options, args = run_tests_util.ParseArgs(
+ 'gtest', argv=['script.py', '-c', 'dbg', '-b'])
+ self.assertEqual(args, ['script.py'])
+ self.assertEqual(options.configurations, 'dbg')
+ self.assertTrue(options.built_configurations)
+
+ def testOptionH(self):
+ help_called = [False]
+
+ # Suppresses lint warning on unused arguments. These arguments are
+ # required by optparse, even though they are unused.
+ # pylint: disable-msg=W0613
+ def VerifyHelp(option, opt, value, parser):
+ help_called[0] = True
+
+ # Verifies that -h causes the help callback to be called.
+ help_called[0] = False
+ _, args = run_tests_util.ParseArgs(
+ 'gtest', argv=['script.py', '-h'], help_callback=VerifyHelp)
+ self.assertEqual(args, ['script.py'])
+ self.assertTrue(help_called[0])
+
+ # Verifies that --help causes the help callback to be called.
+ help_called[0] = False
+ _, args = run_tests_util.ParseArgs(
+ 'gtest', argv=['script.py', '--help'], help_callback=VerifyHelp)
+ self.assertEqual(args, ['script.py'])
+ self.assertTrue(help_called[0])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Source/ThirdParty/gtest/xcode/Config/CompilerVersion.xcconfig b/Source/ThirdParty/gtest/xcode/Config/CompilerVersion.xcconfig
new file mode 100644
index 000000000..a8c7f75a0
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Config/CompilerVersion.xcconfig
@@ -0,0 +1,84 @@
+// Copyright (C) 2009, 2010, 2011 Apple Inc. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+IS_XCODE_0400 = $(IS_XCODE_0400_$(XCODE_VERSION_MINOR));
+IS_XCODE_0400_0400 = YES;
+
+IS_XCODE_0400_OR_0410 = $(IS_XCODE_0400_OR_0410_$(XCODE_VERSION_MINOR));
+IS_XCODE_0400_OR_0410_0400 = YES;
+IS_XCODE_0400_OR_0410_0410 = YES;
+
+// The version of the LLVM Compiler in Xcode 4.0 and earlier have difficulty compiling our code.
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS = $(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_$(XCODE_VERSION_MAJOR));
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_0300 = YES;
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_0400 = $(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_IS_XCODE_0400_$(IS_XCODE_0400));
+LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS_IS_XCODE_0400_YES = YES;
+
+// The version of the LLVM Compiler in Xcode 4.1 and earlier do not generate fast enough code.
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS = $(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_$(XCODE_VERSION_MAJOR));
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_0300 = YES;
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_0400 = $(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_IS_XCODE_0400_OR_0410_$(IS_XCODE_0400_OR_0410));
+LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS_IS_XCODE_0400_OR_0410_YES = YES;
+
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS = $(LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_$(LLVM_COMPILER_UNSUITABLE_FOR_DEBUG_BUILDS));
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_ = YES;
+LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS_YES = NO;
+
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS = $(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_$(LLVM_COMPILER_UNSUITABLE_FOR_OPTIMIZED_BUILDS));
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_ = YES;
+LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS_YES = NO;
+
+
+// Use GCC 4.2 with Xcode 3.1, which includes GCC 4.2 but defaults to GCC 4.0.
+// Note that Xcode versions as new as 3.1.2 use XCODE_VERSION_ACTUAL for the minor version
+// number. Newer versions of Xcode use XCODE_VERSION_MINOR for the minor version, and
+// XCODE_VERSION_ACTUAL for the full version number.
+TARGET_GCC_VERSION = $(TARGET_GCC_VERSION_$(REAL_PLATFORM_NAME));
+TARGET_GCC_VERSION_iphoneos = LLVM_GCC_42;
+TARGET_GCC_VERSION_iphonesimulator = GCC_42;
+TARGET_GCC_VERSION_macosx = $(TARGET_GCC_VERSION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+
+TARGET_GCC_VERSION_macosx_1050 = $(TARGET_GCC_VERSION_macosx_1050_$(XCODE_VERSION_MINOR));
+TARGET_GCC_VERSION_macosx_1050_ = $(TARGET_GCC_VERSION_macosx_1050_$(XCODE_VERSION_ACTUAL));
+TARGET_GCC_VERSION_macosx_1050_0310 = GCC_42;
+TARGET_GCC_VERSION_macosx_1050_0320 = GCC_42;
+
+TARGET_GCC_VERSION_macosx_1060 = $(TARGET_GCC_VERSION_macosx_1060_AND_1070_$(CONFIGURATION));
+TARGET_GCC_VERSION_macosx_1070 = $(TARGET_GCC_VERSION_macosx_1060_AND_1070_$(CONFIGURATION));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Debug = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_DEBUG_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Release = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_AND_1070_Production = $(TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_$(LLVM_COMPILER_SUITABLE_FOR_OPTIMIZED_BUILDS));
+TARGET_GCC_VERSION_macosx_1060_NON_LLVM_FALLBACK = GCC_42;
+TARGET_GCC_VERSION_macosx_1070_NON_LLVM_FALLBACK = LLVM_GCC_42;
+
+TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_YES = LLVM_COMPILER;
+TARGET_GCC_VERSION_macosx_USE_LLVM_COMPILER_NO = $(TARGET_GCC_VERSION_macosx_$(TARGET_MAC_OS_X_VERSION_MAJOR)_NON_LLVM_FALLBACK);
+
+TARGET_GCC_VERSION_macosx_1080 = LLVM_COMPILER;
+TARGET_GCC_VERSION_macosx_1090 = LLVM_COMPILER;
+
+GCC_VERSION = $(GCC_VERSION_$(TARGET_GCC_VERSION));
+GCC_VERSION_GCC_40 = 4.0;
+GCC_VERSION_GCC_42 = 4.2;
+GCC_VERSION_LLVM_GCC_42 = com.apple.compilers.llvmgcc42;
+GCC_VERSION_LLVM_COMPILER = com.apple.compilers.llvm.clang.1_0;
diff --git a/Source/ThirdParty/gtest/xcode/Config/DebugProject.xcconfig b/Source/ThirdParty/gtest/xcode/Config/DebugProject.xcconfig
new file mode 100644
index 000000000..d041f176f
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Config/DebugProject.xcconfig
@@ -0,0 +1,35 @@
+//
+// DebugProject.xcconfig
+//
+// These are Debug Configuration project settings for the gtest framework and
+// examples. It is set in the "Based On:" dropdown in the "Project" info
+// dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+#include "General.xcconfig"
+
+// No optimization
+GCC_OPTIMIZATION_LEVEL = 0
+
+// Deployment postprocessing is what triggers Xcode to strip, turn it off
+DEPLOYMENT_POSTPROCESSING = NO
+
+// Dead code stripping off
+DEAD_CODE_STRIPPING = NO
+
+// Debug symbols should be on obviously
+GCC_GENERATE_DEBUGGING_SYMBOLS = YES
+
+// Define the DEBUG macro in all debug builds
+OTHER_CFLAGS = $(OTHER_CFLAGS) -DDEBUG=1
+
+// These are turned off to avoid STL incompatibilities with client code
+// // Turns on special C++ STL checks to "encourage" good STL use
+// GCC_PREPROCESSOR_DEFINITIONS = $(GCC_PREPROCESSOR_DEFINITIONS) _GLIBCXX_DEBUG_PEDANTIC _GLIBCXX_DEBUG _GLIBCPP_CONCEPT_CHECKS
+
+// Used by HEADER_SEARCH_PATHS in General.xcconfig
+WEBCORE_PRIVATE_HEADERS_DIR = $(BUILT_PRODUCTS_DIR)/WebCore.framework/PrivateHeaders;
+
+ONLY_ACTIVE_ARCH = YES
diff --git a/Source/ThirdParty/gtest/xcode/Config/FrameworkTarget.xcconfig b/Source/ThirdParty/gtest/xcode/Config/FrameworkTarget.xcconfig
new file mode 100644
index 000000000..357b1c8fb
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Config/FrameworkTarget.xcconfig
@@ -0,0 +1,17 @@
+//
+// FrameworkTarget.xcconfig
+//
+// These are Framework target settings for the gtest framework and examples. It
+// is set in the "Based On:" dropdown in the "Target" info dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+// Dynamic libs need to be position independent
+GCC_DYNAMIC_NO_PIC = NO
+
+// Dynamic libs should not have their external symbols stripped.
+STRIP_STYLE = non-global
+
+// Let the user install by specifying the $DSTROOT with xcodebuild
+SKIP_INSTALL = NO
diff --git a/Source/ThirdParty/gtest/xcode/Config/General.xcconfig b/Source/ThirdParty/gtest/xcode/Config/General.xcconfig
new file mode 100644
index 000000000..50b7c2cb8
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Config/General.xcconfig
@@ -0,0 +1,68 @@
+//
+// General.xcconfig
+//
+// These are General configuration settings for the gtest framework and
+// examples.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+#include "CompilerVersion.xcconfig"
+
+// Not building PowerPC any more
+ARCHS = i386 x86_64
+
+HEADER_SEARCH_PATHS = $(WEBCORE_PRIVATE_HEADERS_DIR)/ForwardingHeaders ../ ../include/
+
+// Zerolink prevents link warnings so turn it off
+ZERO_LINK = NO
+
+// Prebinding considered unhelpful in 10.3 and later
+PREBINDING = NO
+
+// Strictest warning policy
+WARNING_CFLAGS = -Wall -Werror -Wendif-labels -Wnewline-eof -Wno-sign-compare -Wshadow
+
+// Work around Xcode bugs by using external strip. See:
+// http://lists.apple.com/archives/Xcode-users/2006/Feb/msg00050.html
+SEPARATE_STRIP = YES
+
+// Force C99 dialect
+GCC_C_LANGUAGE_STANDARD = c99
+
+// not sure why apple defaults this on, but it's pretty risky
+ALWAYS_SEARCH_USER_PATHS = NO
+
+// Turn on position dependent code for most cases (overridden where appropriate)
+GCC_DYNAMIC_NO_PIC = YES
+
+REAL_PLATFORM_NAME = $(REAL_PLATFORM_NAME_$(PLATFORM_NAME));
+REAL_PLATFORM_NAME_ = $(REAL_PLATFORM_NAME_macosx);
+REAL_PLATFORM_NAME_iphoneos = iphoneos;
+REAL_PLATFORM_NAME_iphonesimulator = iphonesimulator;
+REAL_PLATFORM_NAME_macosx = macosx;
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+// If the target Mac OS X version does not match the current Mac OS X version,
+// then we'll want to build using the target version's SDK.
+SDKROOT = $(SDKROOT_$(MAC_OS_X_VERSION_MAJOR)_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+SDKROOT_1050_1040 = macosx10.4;
+SDKROOT_1060_1040 = macosx10.4;
+SDKROOT_1060_1050 = macosx10.5;
+SDKROOT_1070_1040 = macosx10.4;
+SDKROOT_1080_1040 = macosx10.4;
+SDKROOT_1090_1040 = macosx10.4;
+SDKROOT_1070_1050 = macosx10.5;
+SDKROOT_1080_1050 = macosx10.5;
+SDKROOT_1090_1050 = macosx10.5;
+SDKROOT_1070_1060 = macosx10.6;
+SDKROOT_1080_1060 = macosx10.6;
+SDKROOT_1090_1060 = macosx10.6;
+SDKROOT_1080_1070 = macosx10.7;
+SDKROOT_1090_1070 = macosx10.7;
+SDKROOT_1090_1080 = macosx10.8;
+
+
+// VERSIONING BUILD SETTINGS (used in Info.plist)
+GTEST_VERSIONINFO_ABOUT = © 2008 Google Inc.
diff --git a/Source/ThirdParty/gtest/xcode/Config/ProductionProject.xcconfig b/Source/ThirdParty/gtest/xcode/Config/ProductionProject.xcconfig
new file mode 100644
index 000000000..4ba5cbb92
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Config/ProductionProject.xcconfig
@@ -0,0 +1,16 @@
+//
+// ProductionProject.xcconfig
+//
+// These are Production Configuration project settings for the gtest framework
+// and examples. It is set in the "Based On:" dropdown in the "Project" info
+// dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+#include "ReleaseProject.xcconfig"
+
+// Used by HEADER_SEARCH_PATHS in General.xcconfig
+WEBCORE_PRIVATE_HEADERS_DIR = $(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/WebKit.framework/Versions/A/Frameworks/WebCore.framework/PrivateHeaders;
+
+ONLY_ACTIVE_ARCH = NO
diff --git a/Source/ThirdParty/gtest/xcode/Config/ReleaseProject.xcconfig b/Source/ThirdParty/gtest/xcode/Config/ReleaseProject.xcconfig
new file mode 100644
index 000000000..8494769c2
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Config/ReleaseProject.xcconfig
@@ -0,0 +1,37 @@
+//
+// ReleaseProject.xcconfig
+//
+// These are Release Configuration project settings for the gtest framework
+// and examples. It is set in the "Based On:" dropdown in the "Project" info
+// dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+#include "General.xcconfig"
+
+// subconfig/Release.xcconfig
+
+// Optimize for space and size (Apple recommendation)
+GCC_OPTIMIZATION_LEVEL = s
+
+// Deploment postprocessing is what triggers Xcode to strip
+DEPLOYMENT_POSTPROCESSING = YES
+
+// No symbols
+GCC_GENERATE_DEBUGGING_SYMBOLS = NO
+
+// Dead code strip does not affect ObjC code but can help for C
+DEAD_CODE_STRIPPING = YES
+
+// NDEBUG is used by things like assert.h, so define it for general compat.
+// ASSERT going away in release tends to create unused vars.
+OTHER_CFLAGS = $(OTHER_CFLAGS) -DNDEBUG=1 -Wno-unused-variable
+
+// When we strip we want to strip all symbols in release, but save externals.
+STRIP_STYLE = all
+
+// Used by HEADER_SEARCH_PATHS in General.xcconfig
+WEBCORE_PRIVATE_HEADERS_DIR = $(BUILT_PRODUCTS_DIR)/WebCore.framework/PrivateHeaders;
+
+ONLY_ACTIVE_ARCH = YES
diff --git a/Source/ThirdParty/gtest/xcode/Config/StaticLibraryTarget.xcconfig b/Source/ThirdParty/gtest/xcode/Config/StaticLibraryTarget.xcconfig
new file mode 100644
index 000000000..3922fa51d
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Config/StaticLibraryTarget.xcconfig
@@ -0,0 +1,18 @@
+//
+// StaticLibraryTarget.xcconfig
+//
+// These are static library target settings for libgtest.a. It
+// is set in the "Based On:" dropdown in the "Target" info dialog.
+// This file is based on the Xcode Configuration files in:
+// http://code.google.com/p/google-toolbox-for-mac/
+//
+
+// Static libs can be included in bundles so make them position independent
+GCC_DYNAMIC_NO_PIC = NO
+
+// Static libs should not have their internal globals or external symbols
+// stripped.
+STRIP_STYLE = debugging
+
+// Let the user install by specifying the $DSTROOT with xcodebuild
+SKIP_INSTALL = NO
diff --git a/Source/ThirdParty/gtest/xcode/Config/TestTarget.xcconfig b/Source/ThirdParty/gtest/xcode/Config/TestTarget.xcconfig
new file mode 100644
index 000000000..e6652ba85
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Config/TestTarget.xcconfig
@@ -0,0 +1,8 @@
+//
+// TestTarget.xcconfig
+//
+// These are Test target settings for the gtest framework and examples. It
+// is set in the "Based On:" dropdown in the "Target" info dialog.
+
+PRODUCT_NAME = $(TARGET_NAME)
+HEADER_SEARCH_PATHS = ../include
diff --git a/Source/ThirdParty/gtest/xcode/Makefile b/Source/ThirdParty/gtest/xcode/Makefile
new file mode 100644
index 000000000..2c8e8493d
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Makefile
@@ -0,0 +1,2 @@
+SCRIPTS_PATH ?= ../../../../Tools/Scripts
+include ../../../../Makefile.shared
diff --git a/Source/ThirdParty/gtest/xcode/Resources/Info.plist b/Source/ThirdParty/gtest/xcode/Resources/Info.plist
new file mode 100644
index 000000000..9dd28ea14
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Resources/Info.plist
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.${PRODUCT_NAME}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>GTEST_VERSIONINFO_LONG</string>
+ <key>CFBundleShortVersionString</key>
+ <string>GTEST_VERSIONINFO_SHORT</string>
+ <key>CFBundleGetInfoString</key>
+ <string>${PRODUCT_NAME} GTEST_VERSIONINFO_LONG, ${GTEST_VERSIONINFO_ABOUT}</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>${GTEST_VERSIONINFO_ABOUT}</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/Info.plist b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/Info.plist
new file mode 100644
index 000000000..f3852edea
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>com.google.gtest.${PRODUCT_NAME:identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>CSResourcesFileMapped</key>
+ <true/>
+</dict>
+</plist>
diff --git a/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..497617eb6
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj
@@ -0,0 +1,457 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 4024D162113D7D2400C7059E /* Test */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */;
+ buildPhases = (
+ 4024D161113D7D2400C7059E /* ShellScript */,
+ );
+ dependencies = (
+ 4024D166113D7D3100C7059E /* PBXTargetDependency */,
+ );
+ name = Test;
+ productName = TestAndBuild;
+ };
+ 4024D1E9113D83FF00C7059E /* TestAndBuild */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 4024D1ED113D840900C7059E /* PBXTargetDependency */,
+ 4024D1EF113D840D00C7059E /* PBXTargetDependency */,
+ );
+ name = TestAndBuild;
+ productName = TestAndBuild;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1230E5AEE3500C7F239 /* widget.cc */; };
+ 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B7EB1240E5AEE3500C7F239 /* widget.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */; };
+ 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */; };
+ 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D185113D7D5500C7059E /* libgtest.a */; };
+ 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4024D183113D7D5500C7059E /* libgtest_main.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = gTestExample;
+ };
+ 4024D165113D7D3100C7059E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 3B07BDE90E3F3F9E00647869;
+ remoteInfo = WidgetFrameworkTest;
+ };
+ 4024D1EC113D840900C7059E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = WidgetFramework;
+ };
+ 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4024D162113D7D2400C7059E;
+ remoteInfo = Test;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WidgetFrameworkTest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3B7EB1230E5AEE3500C7F239 /* widget.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget.cc; sourceTree = "<group>"; };
+ 3B7EB1240E5AEE3500C7F239 /* widget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = widget.h; sourceTree = "<group>"; };
+ 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget_test.cc; sourceTree = "<group>"; };
+ 4024D183113D7D5500C7059E /* libgtest_main.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest_main.a; path = /usr/local/lib/libgtest_main.a; sourceTree = "<absolute>"; };
+ 4024D185113D7D5500C7059E /* libgtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest.a; path = /usr/local/lib/libgtest.a; sourceTree = "<absolute>"; };
+ 4024D1E2113D838200C7059E /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = "<group>"; };
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+ 8D07F2C80486CC7A007CD1D0 /* Widget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Widget.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 3B07BDE80E3F3F9E00647869 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4024D189113D7D7A00C7059E /* libgtest_main.a in Frameworks */,
+ 4024D188113D7D7800C7059E /* libgtest.a in Frameworks */,
+ 3B7EB1480E5AF3B400C7F239 /* Widget.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C80486CC7A007CD1D0 /* Widget.framework */,
+ 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* gTestExample */ = {
+ isa = PBXGroup;
+ children = (
+ 4024D1E1113D836C00C7059E /* Scripts */,
+ 08FB77ACFE841707C02AAC07 /* Source */,
+ 089C1665FE841158C02AAC07 /* Resources */,
+ 3B07BE350E4094E400647869 /* Test */,
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = gTestExample;
+ sourceTree = "<group>";
+ };
+ 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 4024D183113D7D5500C7059E /* libgtest_main.a */,
+ 4024D185113D7D5500C7059E /* libgtest.a */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 089C1665FE841158C02AAC07 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 8D07F2C70486CC7A007CD1D0 /* Info.plist */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 08FB77ACFE841707C02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 3B7EB1230E5AEE3500C7F239 /* widget.cc */,
+ 3B7EB1240E5AEE3500C7F239 /* widget.h */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 3B07BE350E4094E400647869 /* Test */ = {
+ isa = PBXGroup;
+ children = (
+ 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */,
+ );
+ name = Test;
+ sourceTree = "<group>";
+ };
+ 4024D1E1113D836C00C7059E /* Scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 4024D1E2113D838200C7059E /* runtests.sh */,
+ );
+ name = Scripts;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3B7EB1260E5AEE3500C7F239 /* widget.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */;
+ buildPhases = (
+ 3B07BDE70E3F3F9E00647869 /* Sources */,
+ 3B07BDE80E3F3F9E00647869 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */,
+ );
+ name = WidgetFrameworkTest;
+ productName = gTestExampleTest;
+ productReference = 3B07BDEA0E3F3F9E00647869 /* WidgetFrameworkTest */;
+ productType = "com.apple.product-type.tool";
+ };
+ 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */;
+ buildPhases = (
+ 8D07F2C10486CC7A007CD1D0 /* Sources */,
+ 8D07F2C30486CC7A007CD1D0 /* Frameworks */,
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */,
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */,
+ 8D07F2C50486CC7A007CD1D0 /* Rez */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = WidgetFramework;
+ productInstallPath = "$(HOME)/Library/Frameworks";
+ productName = gTestExample;
+ productReference = 8D07F2C80486CC7A007CD1D0 /* Widget.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */;
+ compatibilityVersion = "Xcode 2.4";
+ hasScannedForEncodings = 1;
+ mainGroup = 0867D691FE84028FC02AAC07 /* gTestExample */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */,
+ 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */,
+ 4024D162113D7D2400C7059E /* Test */,
+ 4024D1E9113D83FF00C7059E /* TestAndBuild */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ 8D07F2C50486CC7A007CD1D0 /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 4024D161113D7D2400C7059E /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/bash $SRCROOT/runtests.sh $BUILT_PRODUCTS_DIR/WidgetFrameworkTest\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 3B07BDE70E3F3F9E00647869 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3B7EB1280E5AEE4600C7F239 /* widget_test.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D07F2C10486CC7A007CD1D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3B7EB1250E5AEE3500C7F239 /* widget.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 3B07BDF10E3F3FAE00647869 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */;
+ targetProxy = 3B07BDF00E3F3FAE00647869 /* PBXContainerItemProxy */;
+ };
+ 4024D166113D7D3100C7059E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 3B07BDE90E3F3F9E00647869 /* WidgetFrameworkTest */;
+ targetProxy = 4024D165113D7D3100C7059E /* PBXContainerItemProxy */;
+ };
+ 4024D1ED113D840900C7059E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D07F2BC0486CC7A007CD1D0 /* WidgetFramework */;
+ targetProxy = 4024D1EC113D840900C7059E /* PBXContainerItemProxy */;
+ };
+ 4024D1EF113D840D00C7059E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4024D162113D7D2400C7059E /* Test */;
+ targetProxy = 4024D1EE113D840D00C7059E /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 3B07BDEC0E3F3F9F00647869 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = WidgetFrameworkTest;
+ };
+ name = Debug;
+ };
+ 3B07BDED0E3F3F9F00647869 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = WidgetFrameworkTest;
+ };
+ name = Release;
+ };
+ 4024D163113D7D2400C7059E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = TestAndBuild;
+ };
+ name = Debug;
+ };
+ 4024D164113D7D2400C7059E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = TestAndBuild;
+ };
+ name = Release;
+ };
+ 4024D1EA113D83FF00C7059E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = TestAndBuild;
+ };
+ name = Debug;
+ };
+ 4024D1EB113D83FF00C7059E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = TestAndBuild;
+ };
+ name = Release;
+ };
+ 4FADC24308B4156D00ABE55E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@loader_path/../Frameworks";
+ PRODUCT_NAME = Widget;
+ };
+ name = Debug;
+ };
+ 4FADC24408B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ FRAMEWORK_VERSION = A;
+ INFOPLIST_FILE = Info.plist;
+ INSTALL_PATH = "@loader_path/../Frameworks";
+ PRODUCT_NAME = Widget;
+ };
+ name = Release;
+ };
+ 4FADC24708B4156D00ABE55E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_VERSION = 4.0;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Debug;
+ };
+ 4FADC24808B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_VERSION = 4.0;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 3B07BDF40E3F3FB600647869 /* Build configuration list for PBXNativeTarget "WidgetFrameworkTest" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 3B07BDEC0E3F3F9F00647869 /* Debug */,
+ 3B07BDED0E3F3F9F00647869 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4024D169113D7D4600C7059E /* Build configuration list for PBXAggregateTarget "Test" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4024D163113D7D2400C7059E /* Debug */,
+ 4024D164113D7D2400C7059E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4024D1F0113D842B00C7059E /* Build configuration list for PBXAggregateTarget "TestAndBuild" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4024D1EA113D83FF00C7059E /* Debug */,
+ 4024D1EB113D83FF00C7059E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "WidgetFramework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24308B4156D00ABE55E /* Debug */,
+ 4FADC24408B4156D00ABE55E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "WidgetFramework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24708B4156D00ABE55E /* Debug */,
+ 4FADC24808B4156D00ABE55E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/runtests.sh b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/runtests.sh
new file mode 100644
index 000000000..4a0d413e5
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/runtests.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Executes the samples and tests for the Google Test Framework.
+
+# Help the dynamic linker find the path to the libraries.
+export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR
+export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR
+
+# Create some executables.
+test_executables=$@
+
+# Now execute each one in turn keeping track of how many succeeded and failed.
+succeeded=0
+failed=0
+failed_list=()
+for test in ${test_executables[*]}; do
+ "$test"
+ result=$?
+ if [ $result -eq 0 ]; then
+ succeeded=$(( $succeeded + 1 ))
+ else
+ failed=$(( failed + 1 ))
+ failed_list="$failed_list $test"
+ fi
+done
+
+# Report the successes and failures to the console.
+echo "Tests complete with $succeeded successes and $failed failures."
+if [ $failed -ne 0 ]; then
+ echo "The following tests failed:"
+ echo $failed_list
+fi
+exit $failed
diff --git a/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget.cc b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget.cc
new file mode 100644
index 000000000..bfc4e7fcf
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget.cc
@@ -0,0 +1,63 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: preston.a.jackson@gmail.com (Preston Jackson)
+//
+// Google Test - FrameworkSample
+// widget.cc
+//
+
+// Widget is a very simple class used for demonstrating the use of gtest
+
+#include "widget.h"
+
+Widget::Widget(int number, const std::string& name)
+ : number_(number),
+ name_(name) {}
+
+Widget::~Widget() {}
+
+float Widget::GetFloatValue() const {
+ return number_;
+}
+
+int Widget::GetIntValue() const {
+ return static_cast<int>(number_);
+}
+
+std::string Widget::GetStringValue() const {
+ return name_;
+}
+
+void Widget::GetCharPtrValue(char* buffer, size_t max_size) const {
+ // Copy the char* representation of name_ into buffer, up to max_size.
+ strncpy(buffer, name_.c_str(), max_size-1);
+ buffer[max_size-1] = '\0';
+ return;
+}
diff --git a/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget.h b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget.h
new file mode 100644
index 000000000..0c55cdc8c
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget.h
@@ -0,0 +1,59 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: preston.a.jackson@gmail.com (Preston Jackson)
+//
+// Google Test - FrameworkSample
+// widget.h
+//
+
+// Widget is a very simple class used for demonstrating the use of gtest. It
+// simply stores two values a string and an integer, which are returned via
+// public accessors in multiple forms.
+
+#import <string>
+
+class Widget {
+ public:
+ Widget(int number, const std::string& name);
+ ~Widget();
+
+ // Public accessors to number data
+ float GetFloatValue() const;
+ int GetIntValue() const;
+
+ // Public accessors to the string data
+ std::string GetStringValue() const;
+ void GetCharPtrValue(char* buffer, size_t max_size) const;
+
+ private:
+ // Data members
+ float number_;
+ std::string name_;
+};
diff --git a/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget_test.cc b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget_test.cc
new file mode 100644
index 000000000..61c0d2ffd
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Samples/FrameworkSample/widget_test.cc
@@ -0,0 +1,68 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: preston.a.jackson@gmail.com (Preston Jackson)
+//
+// Google Test - FrameworkSample
+// widget_test.cc
+//
+
+// This is a simple test file for the Widget class in the Widget.framework
+
+#include <string>
+#include <gtest/gtest.h>
+
+#include <Widget/widget.h>
+
+// This test verifies that the constructor sets the internal state of the
+// Widget class correctly.
+TEST(WidgetInitializerTest, TestConstructor) {
+ Widget widget(1.0f, "name");
+ EXPECT_FLOAT_EQ(1.0f, widget.GetFloatValue());
+ EXPECT_EQ(std::string("name"), widget.GetStringValue());
+}
+
+// This test verifies the conversion of the float and string values to int and
+// char*, respectively.
+TEST(WidgetInitializerTest, TestConversion) {
+ Widget widget(1.0f, "name");
+ EXPECT_EQ(1, widget.GetIntValue());
+
+ size_t max_size = 128;
+ char buffer[max_size];
+ widget.GetCharPtrValue(buffer, max_size);
+ EXPECT_STREQ("name", buffer);
+}
+
+// Use the Google Test main that is linked into the framework. It does something
+// like this:
+// int main(int argc, char** argv) {
+// testing::InitGoogleTest(&argc, argv);
+// return RUN_ALL_TESTS();
+// }
diff --git a/Source/ThirdParty/gtest/xcode/Scripts/runtests.sh b/Source/ThirdParty/gtest/xcode/Scripts/runtests.sh
new file mode 100644
index 000000000..3fc229f1d
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Scripts/runtests.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Executes the samples and tests for the Google Test Framework.
+
+# Help the dynamic linker find the path to the libraries.
+export DYLD_FRAMEWORK_PATH=$BUILT_PRODUCTS_DIR
+export DYLD_LIBRARY_PATH=$BUILT_PRODUCTS_DIR
+
+# Create some executables.
+test_executables=("$BUILT_PRODUCTS_DIR/gtest_unittest-framework"
+ "$BUILT_PRODUCTS_DIR/gtest_unittest"
+ "$BUILT_PRODUCTS_DIR/sample1_unittest-framework"
+ "$BUILT_PRODUCTS_DIR/sample1_unittest-static")
+
+# Now execute each one in turn keeping track of how many succeeded and failed.
+succeeded=0
+failed=0
+failed_list=()
+for test in ${test_executables[*]}; do
+ "$test"
+ result=$?
+ if [ $result -eq 0 ]; then
+ succeeded=$(( $succeeded + 1 ))
+ else
+ failed=$(( failed + 1 ))
+ failed_list="$failed_list $test"
+ fi
+done
+
+# Report the successes and failures to the console.
+echo "Tests complete with $succeeded successes and $failed failures."
+if [ $failed -ne 0 ]; then
+ echo "The following tests failed:"
+ echo $failed_list
+fi
+exit $failed
diff --git a/Source/ThirdParty/gtest/xcode/Scripts/versiongenerate.py b/Source/ThirdParty/gtest/xcode/Scripts/versiongenerate.py
new file mode 100644
index 000000000..81de8c96a
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/Scripts/versiongenerate.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+#
+# Copyright 2008, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""A script to prepare version informtion for use the gtest Info.plist file.
+
+ This script extracts the version information from the configure.ac file and
+ uses it to generate a header file containing the same information. The
+ #defines in this header file will be included in during the generation of
+ the Info.plist of the framework, giving the correct value to the version
+ shown in the Finder.
+
+ This script makes the following assumptions (these are faults of the script,
+ not problems with the Autoconf):
+ 1. The AC_INIT macro will be contained within the first 1024 characters
+ of configure.ac
+ 2. The version string will be 3 integers separated by periods and will be
+ surrounded by squre brackets, "[" and "]" (e.g. [1.0.1]). The first
+ segment represents the major version, the second represents the minor
+ version and the third represents the fix version.
+ 3. No ")" character exists between the opening "(" and closing ")" of
+ AC_INIT, including in comments and character strings.
+"""
+
+import sys
+import re
+
+# Read the command line argument (the output directory for Version.h)
+if (len(sys.argv) < 3):
+ print "Usage: versiongenerate.py input_dir output_dir"
+ sys.exit(1)
+else:
+ input_dir = sys.argv[1]
+ output_dir = sys.argv[2]
+
+# Read the first 1024 characters of the configure.ac file
+config_file = open("%s/configure.ac" % input_dir, 'r')
+buffer_size = 1024
+opening_string = config_file.read(buffer_size)
+config_file.close()
+
+# Extract the version string from the AC_INIT macro
+# The following init_expression means:
+# Extract three integers separated by periods and surrounded by squre
+# brackets(e.g. "[1.0.1]") between "AC_INIT(" and ")". Do not be greedy
+# (*? is the non-greedy flag) since that would pull in everything between
+# the first "(" and the last ")" in the file.
+version_expression = re.compile(r"AC_INIT\(.*?\[(\d+)\.(\d+)\.(\d+)\].*?\)",
+ re.DOTALL)
+version_values = version_expression.search(opening_string)
+major_version = version_values.group(1)
+minor_version = version_values.group(2)
+fix_version = version_values.group(3)
+
+# Write the version information to a header file to be included in the
+# Info.plist file.
+file_data = """//
+// DO NOT MODIFY THIS FILE (but you can delete it)
+//
+// This file is autogenerated by the versiongenerate.py script. This script
+// is executed in a "Run Script" build phase when creating gtest.framework. This
+// header file is not used during compilation of C-source. Rather, it simply
+// defines some version strings for substitution in the Info.plist. Because of
+// this, we are not not restricted to C-syntax nor are we using include guards.
+//
+
+#define GTEST_VERSIONINFO_SHORT %s.%s
+#define GTEST_VERSIONINFO_LONG %s.%s.%s
+
+""" % (major_version, minor_version, major_version, minor_version, fix_version)
+version_file = open("%s/Version.h" % output_dir, 'w')
+version_file.write(file_data)
+version_file.close()
diff --git a/Source/ThirdParty/gtest/xcode/gtest.xcodeproj/project.pbxproj b/Source/ThirdParty/gtest/xcode/gtest.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..5f641e9ed
--- /dev/null
+++ b/Source/ThirdParty/gtest/xcode/gtest.xcodeproj/project.pbxproj
@@ -0,0 +1,1163 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 3B238F5F0E828B5400846E11 /* Check */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */;
+ buildPhases = (
+ 3B238F5E0E828B5400846E11 /* ShellScript */,
+ );
+ dependencies = (
+ 40899F9D0FFA740F000B29AE /* PBXTargetDependency */,
+ 40C849F7101A43440083642A /* PBXTargetDependency */,
+ 4089A0980FFAD34A000B29AE /* PBXTargetDependency */,
+ 40C849F9101A43490083642A /* PBXTargetDependency */,
+ );
+ name = Check;
+ productName = Check;
+ };
+ 40C44ADC0E3798F4008FCC51 /* Version Info */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */;
+ buildPhases = (
+ 40C44ADB0E3798F4008FCC51 /* Generate Version.h */,
+ );
+ comments = "The generation of Version.h must be performed in its own target. Since the Info.plist is preprocessed before any of the other build phases in gtest, the Version.h file would not be ready if included as a build phase of that target.";
+ dependencies = (
+ );
+ name = "Version Info";
+ productName = Version.h;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */ = {isa = PBXBuildFile; fileRef = 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */; };
+ 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DB0E2F799B00CF7658 /* gtest-death-test.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 404884390E2F799B00CF7658 /* gtest-message.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DC0E2F799B00CF7658 /* gtest-message.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DD0E2F799B00CF7658 /* gtest-spi.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4048843B0E2F799B00CF7658 /* gtest.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DE0E2F799B00CF7658 /* gtest.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */ = {isa = PBXBuildFile; fileRef = 404883E00E2F799B00CF7658 /* gtest_prod.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 404884500E2F799B00CF7658 /* README in Resources */ = {isa = PBXBuildFile; fileRef = 404883F60E2F799B00CF7658 /* README */; };
+ 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */; };
+ 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E30E2F799B00CF7658 /* gtest-filepath.h */; };
+ 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E40E2F799B00CF7658 /* gtest-internal.h */; };
+ 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E50E2F799B00CF7658 /* gtest-port.h */; };
+ 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 404883E60E2F799B00CF7658 /* gtest-string.h */; };
+ 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */ = {isa = PBXBuildFile; fileRef = 404884A90E2F7CD900CF7658 /* CHANGES */; };
+ 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */ = {isa = PBXBuildFile; fileRef = 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */; };
+ 404884AE0E2F7CD900CF7658 /* COPYING in Resources */ = {isa = PBXBuildFile; fileRef = 404884AB0E2F7CD900CF7658 /* COPYING */; };
+ 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; };
+ 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 40899F4D0FFA7271000B29AE /* gtest-tuple.h */; };
+ 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; };
+ 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; };
+ 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; };
+ 40C848FF101A21150083642A /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = 224A12A10E9EADA700BD17FD /* gtest-all.cc */; };
+ 40C84915101A21DF0083642A /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4048840D0E2F799B00CF7658 /* gtest_main.cc */; };
+ 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C84978101A36540083642A /* libgtest_main.a in Resources */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C84980101A36850083642A /* gtest_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */; };
+ 40C84982101A36850083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; };
+ 40C84983101A36850083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C8498F101A36A60083642A /* sample1.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02C0FFACF7F000B29AE /* sample1.cc */; };
+ 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */; };
+ 40C84992101A36A60083642A /* libgtest.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C848FA101A209C0083642A /* libgtest.a */; };
+ 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 40C8490B101A217E0083642A /* libgtest_main.a */; };
+ 40C849A2101A37050083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; };
+ 40C849A4101A37150083642A /* gtest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4539C8FF0EC27F6400A70F4C /* gtest.framework */; };
+ 444D117514A262FB009FEC3F /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 444D117414A262FB009FEC3F /* JavaScriptCore.framework */; };
+ 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */ = {isa = PBXBuildFile; fileRef = 4539C9330EC280AE00A70F4C /* gtest-param-test.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */; };
+ 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */; };
+ 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */ = {isa = PBXBuildFile; fileRef = 4539C9370EC280E200A70F4C /* gtest-param-util.h */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40899F420FFA7184000B29AE;
+ remoteInfo = gtest_unittest;
+ };
+ 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4089A0120FFACEFC000B29AE;
+ remoteInfo = sample1_unittest;
+ };
+ 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C848F9101A209C0083642A;
+ remoteInfo = "gtest-static";
+ };
+ 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C44ADC0E3798F4008FCC51;
+ remoteInfo = Version.h;
+ };
+ 40C8497C101A36850083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C848F9101A209C0083642A;
+ remoteInfo = "gtest-static";
+ };
+ 40C8497E101A36850083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C8490A101A217E0083642A;
+ remoteInfo = "gtest_main-static";
+ };
+ 40C8498B101A36A60083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C848F9101A209C0083642A;
+ remoteInfo = "gtest-static";
+ };
+ 40C8498D101A36A60083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C8490A101A217E0083642A;
+ remoteInfo = "gtest_main-static";
+ };
+ 40C8499B101A36DC0083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C8490A101A217E0083642A;
+ remoteInfo = "gtest_main-static";
+ };
+ 40C8499D101A36E50083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = "gtest-framework";
+ };
+ 40C8499F101A36F10083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8D07F2BC0486CC7A007CD1D0;
+ remoteInfo = "gtest-framework";
+ };
+ 40C849F6101A43440083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C8497A101A36850083642A;
+ remoteInfo = "gtest_unittest-static";
+ };
+ 40C849F8101A43490083642A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 40C84989101A36A60083642A;
+ remoteInfo = "sample1_unittest-static";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 404884A50E2F7C0400CF7658 /* Copy Headers Internal */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = Headers/internal;
+ dstSubfolderSpec = 6;
+ files = (
+ 404884A00E2F7BE600CF7658 /* gtest-death-test-internal.h in Copy Headers Internal */,
+ 404884A10E2F7BE600CF7658 /* gtest-filepath.h in Copy Headers Internal */,
+ 404884A20E2F7BE600CF7658 /* gtest-internal.h in Copy Headers Internal */,
+ 4539C9380EC280E200A70F4C /* gtest-linked_ptr.h in Copy Headers Internal */,
+ 4539C9390EC280E200A70F4C /* gtest-param-util-generated.h in Copy Headers Internal */,
+ 4539C93A0EC280E200A70F4C /* gtest-param-util.h in Copy Headers Internal */,
+ 404884A30E2F7BE600CF7658 /* gtest-port.h in Copy Headers Internal */,
+ 404884A40E2F7BE600CF7658 /* gtest-string.h in Copy Headers Internal */,
+ 40899F500FFA7281000B29AE /* gtest-tuple.h in Copy Headers Internal */,
+ 3BF6F2A00E79B5AD000F2EEE /* gtest-type-util.h in Copy Headers Internal */,
+ );
+ name = "Copy Headers Internal";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 224A12A10E9EADA700BD17FD /* gtest-all.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = "gtest-all.cc"; sourceTree = "<group>"; };
+ 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "gtest-test-part.h"; sourceTree = "<group>"; };
+ 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_unittest.cc; sourceTree = "<group>"; };
+ 3B87D2100E96B92E000D1852 /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = "<group>"; };
+ 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-type-util.h"; sourceTree = "<group>"; };
+ 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-typed-test.h"; sourceTree = "<group>"; };
+ 403EE37C0E377822004BD1E2 /* versiongenerate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = versiongenerate.py; sourceTree = "<group>"; };
+ 404883DB0E2F799B00CF7658 /* gtest-death-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test.h"; sourceTree = "<group>"; };
+ 404883DC0E2F799B00CF7658 /* gtest-message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-message.h"; sourceTree = "<group>"; };
+ 404883DD0E2F799B00CF7658 /* gtest-spi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-spi.h"; sourceTree = "<group>"; };
+ 404883DE0E2F799B00CF7658 /* gtest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest.h; sourceTree = "<group>"; };
+ 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_pred_impl.h; sourceTree = "<group>"; };
+ 404883E00E2F799B00CF7658 /* gtest_prod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_prod.h; sourceTree = "<group>"; };
+ 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test-internal.h"; sourceTree = "<group>"; };
+ 404883E30E2F799B00CF7658 /* gtest-filepath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-filepath.h"; sourceTree = "<group>"; };
+ 404883E40E2F799B00CF7658 /* gtest-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-internal.h"; sourceTree = "<group>"; };
+ 404883E50E2F799B00CF7658 /* gtest-port.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-port.h"; sourceTree = "<group>"; };
+ 404883E60E2F799B00CF7658 /* gtest-string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-string.h"; sourceTree = "<group>"; };
+ 404883F60E2F799B00CF7658 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README; path = ../README; sourceTree = SOURCE_ROOT; };
+ 4048840D0E2F799B00CF7658 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_main.cc; sourceTree = "<group>"; };
+ 404884A90E2F7CD900CF7658 /* CHANGES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CHANGES; path = ../CHANGES; sourceTree = SOURCE_ROOT; };
+ 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = CONTRIBUTORS; path = ../CONTRIBUTORS; sourceTree = SOURCE_ROOT; };
+ 404884AB0E2F7CD900CF7658 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = COPYING; path = ../COPYING; sourceTree = SOURCE_ROOT; };
+ 40899F430FFA7184000B29AE /* gtest_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "gtest_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40899F4D0FFA7271000B29AE /* gtest-tuple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-tuple.h"; sourceTree = "<group>"; };
+ 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StaticLibraryTarget.xcconfig; sourceTree = "<group>"; };
+ 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-framework"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4089A02C0FFACF7F000B29AE /* sample1.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1.cc; sourceTree = "<group>"; };
+ 4089A02D0FFACF7F000B29AE /* sample1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sample1.h; sourceTree = "<group>"; };
+ 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1_unittest.cc; sourceTree = "<group>"; };
+ 40C848FA101A209C0083642A /* libgtest.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40C8490B101A217E0083642A /* libgtest_main.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libgtest_main.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40C84987101A36850083642A /* gtest_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gtest_unittest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40C84997101A36A60083642A /* sample1_unittest-static */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "sample1_unittest-static"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugProject.xcconfig; sourceTree = "<group>"; };
+ 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FrameworkTarget.xcconfig; sourceTree = "<group>"; };
+ 40D4CDF30E30E07400294801 /* General.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = General.xcconfig; sourceTree = "<group>"; };
+ 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseProject.xcconfig; sourceTree = "<group>"; };
+ 40D4CF510E30F5E200294801 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ 444D117414A262FB009FEC3F /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 44C48DFF14A4098F00A2D9C7 /* ProductionProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ProductionProject.xcconfig; sourceTree = "<group>"; };
+ 4539C8FF0EC27F6400A70F4C /* gtest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = gtest.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4539C9330EC280AE00A70F4C /* gtest-param-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-test.h"; sourceTree = "<group>"; };
+ 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-linked_ptr.h"; sourceTree = "<group>"; };
+ 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util-generated.h"; sourceTree = "<group>"; };
+ 4539C9370EC280E200A70F4C /* gtest-param-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util.h"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 40899F410FFA7184000B29AE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C849A4101A37150083642A /* gtest.framework in Frameworks */,
+ 40C84916101A235B0083642A /* libgtest_main.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4089A0110FFACEFC000B29AE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C849A2101A37050083642A /* gtest.framework in Frameworks */,
+ 40C84921101A23AD0083642A /* libgtest_main.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C84981101A36850083642A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C84982101A36850083642A /* libgtest.a in Frameworks */,
+ 40C84983101A36850083642A /* libgtest_main.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C84991101A36A60083642A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C84992101A36A60083642A /* libgtest.a in Frameworks */,
+ 40C84993101A36A60083642A /* libgtest_main.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 444D117214A2628F009FEC3F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 444D117514A262FB009FEC3F /* JavaScriptCore.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 034768DDFF38A45A11DB9C8B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 4539C8FF0EC27F6400A70F4C /* gtest.framework */,
+ 40C848FA101A209C0083642A /* libgtest.a */,
+ 40C8490B101A217E0083642A /* libgtest_main.a */,
+ 40899F430FFA7184000B29AE /* gtest_unittest-framework */,
+ 40C84987101A36850083642A /* gtest_unittest */,
+ 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */,
+ 40C84997101A36A60083642A /* sample1_unittest-static */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0867D691FE84028FC02AAC07 /* gtest */ = {
+ isa = PBXGroup;
+ children = (
+ 444D117414A262FB009FEC3F /* JavaScriptCore.framework */,
+ 40D4CDF00E30E07400294801 /* Config */,
+ 08FB77ACFE841707C02AAC07 /* Source */,
+ 40D4CF4E0E30F5E200294801 /* Resources */,
+ 403EE37B0E377822004BD1E2 /* Scripts */,
+ 034768DDFF38A45A11DB9C8B /* Products */,
+ );
+ name = gtest;
+ sourceTree = "<group>";
+ };
+ 08FB77ACFE841707C02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 404884A90E2F7CD900CF7658 /* CHANGES */,
+ 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */,
+ 404884AB0E2F7CD900CF7658 /* COPYING */,
+ 404883F60E2F799B00CF7658 /* README */,
+ 404883D90E2F799B00CF7658 /* include */,
+ 4089A02F0FFACF84000B29AE /* samples */,
+ 404884070E2F799B00CF7658 /* src */,
+ 3B238BF00E7FE13B00846E11 /* test */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 3B238BF00E7FE13B00846E11 /* test */ = {
+ isa = PBXGroup;
+ children = (
+ 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */,
+ );
+ name = test;
+ path = ../test;
+ sourceTree = SOURCE_ROOT;
+ };
+ 403EE37B0E377822004BD1E2 /* Scripts */ = {
+ isa = PBXGroup;
+ children = (
+ 403EE37C0E377822004BD1E2 /* versiongenerate.py */,
+ 3B87D2100E96B92E000D1852 /* runtests.sh */,
+ );
+ path = Scripts;
+ sourceTree = "<group>";
+ };
+ 404883D90E2F799B00CF7658 /* include */ = {
+ isa = PBXGroup;
+ children = (
+ 404883DA0E2F799B00CF7658 /* gtest */,
+ );
+ name = include;
+ path = ../include;
+ sourceTree = SOURCE_ROOT;
+ };
+ 404883DA0E2F799B00CF7658 /* gtest */ = {
+ isa = PBXGroup;
+ children = (
+ 404883E10E2F799B00CF7658 /* internal */,
+ 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */,
+ 404883DB0E2F799B00CF7658 /* gtest-death-test.h */,
+ 404883DC0E2F799B00CF7658 /* gtest-message.h */,
+ 4539C9330EC280AE00A70F4C /* gtest-param-test.h */,
+ 404883DD0E2F799B00CF7658 /* gtest-spi.h */,
+ 404883DE0E2F799B00CF7658 /* gtest.h */,
+ 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */,
+ 404883E00E2F799B00CF7658 /* gtest_prod.h */,
+ 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */,
+ );
+ path = gtest;
+ sourceTree = "<group>";
+ };
+ 404883E10E2F799B00CF7658 /* internal */ = {
+ isa = PBXGroup;
+ children = (
+ 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */,
+ 404883E30E2F799B00CF7658 /* gtest-filepath.h */,
+ 404883E40E2F799B00CF7658 /* gtest-internal.h */,
+ 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */,
+ 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */,
+ 4539C9370EC280E200A70F4C /* gtest-param-util.h */,
+ 404883E50E2F799B00CF7658 /* gtest-port.h */,
+ 404883E60E2F799B00CF7658 /* gtest-string.h */,
+ 40899F4D0FFA7271000B29AE /* gtest-tuple.h */,
+ 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */,
+ );
+ path = internal;
+ sourceTree = "<group>";
+ };
+ 404884070E2F799B00CF7658 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ 224A12A10E9EADA700BD17FD /* gtest-all.cc */,
+ 4048840D0E2F799B00CF7658 /* gtest_main.cc */,
+ );
+ name = src;
+ path = ../src;
+ sourceTree = SOURCE_ROOT;
+ };
+ 4089A02F0FFACF84000B29AE /* samples */ = {
+ isa = PBXGroup;
+ children = (
+ 4089A02C0FFACF7F000B29AE /* sample1.cc */,
+ 4089A02D0FFACF7F000B29AE /* sample1.h */,
+ 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */,
+ );
+ name = samples;
+ path = ../samples;
+ sourceTree = SOURCE_ROOT;
+ };
+ 40D4CDF00E30E07400294801 /* Config */ = {
+ isa = PBXGroup;
+ children = (
+ 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */,
+ 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */,
+ 40D4CDF30E30E07400294801 /* General.xcconfig */,
+ 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */,
+ 44C48DFF14A4098F00A2D9C7 /* ProductionProject.xcconfig */,
+ 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */,
+ );
+ path = Config;
+ sourceTree = "<group>";
+ };
+ 40D4CF4E0E30F5E200294801 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 40D4CF510E30F5E200294801 /* Info.plist */,
+ );
+ path = Resources;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 404884380E2F799B00CF7658 /* gtest-death-test.h in Headers */,
+ 404884390E2F799B00CF7658 /* gtest-message.h in Headers */,
+ 4539C9340EC280AE00A70F4C /* gtest-param-test.h in Headers */,
+ 3BF6F2A50E79B616000F2EEE /* gtest-typed-test.h in Headers */,
+ 4048843A0E2F799B00CF7658 /* gtest-spi.h in Headers */,
+ 4048843B0E2F799B00CF7658 /* gtest.h in Headers */,
+ 4048843C0E2F799B00CF7658 /* gtest_pred_impl.h in Headers */,
+ 4048843D0E2F799B00CF7658 /* gtest_prod.h in Headers */,
+ 224A12A30E9EADCC00BD17FD /* gtest-test-part.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 40899F420FFA7184000B29AE /* gtest_unittest-framework */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */;
+ buildPhases = (
+ 40899F400FFA7184000B29AE /* Sources */,
+ 40899F410FFA7184000B29AE /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C849A0101A36F10083642A /* PBXTargetDependency */,
+ );
+ name = "gtest_unittest-framework";
+ productName = gtest_unittest;
+ productReference = 40899F430FFA7184000B29AE /* gtest_unittest-framework */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */;
+ buildPhases = (
+ 4089A0100FFACEFC000B29AE /* Sources */,
+ 4089A0110FFACEFC000B29AE /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C8499E101A36E50083642A /* PBXTargetDependency */,
+ );
+ name = "sample1_unittest-framework";
+ productName = sample1_unittest;
+ productReference = 4089A0130FFACEFC000B29AE /* sample1_unittest-framework */;
+ productType = "com.apple.product-type.tool";
+ };
+ 40C848F9101A209C0083642A /* gtest-static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */;
+ buildPhases = (
+ 40C848F7101A209C0083642A /* Sources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "gtest-static";
+ productName = "gtest-static";
+ productReference = 40C848FA101A209C0083642A /* libgtest.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 40C8490A101A217E0083642A /* gtest_main-static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */;
+ buildPhases = (
+ 40C84908101A217E0083642A /* Sources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "gtest_main-static";
+ productName = "gtest_main-static";
+ productReference = 40C8490B101A217E0083642A /* libgtest_main.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 40C8497A101A36850083642A /* gtest_unittest-static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */;
+ buildPhases = (
+ 40C8497F101A36850083642A /* Sources */,
+ 40C84981101A36850083642A /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C8497B101A36850083642A /* PBXTargetDependency */,
+ 40C8497D101A36850083642A /* PBXTargetDependency */,
+ );
+ name = "gtest_unittest-static";
+ productName = gtest_unittest;
+ productReference = 40C84987101A36850083642A /* gtest_unittest */;
+ productType = "com.apple.product-type.tool";
+ };
+ 40C84989101A36A60083642A /* sample1_unittest-static */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */;
+ buildPhases = (
+ 40C8498E101A36A60083642A /* Sources */,
+ 40C84991101A36A60083642A /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C8498A101A36A60083642A /* PBXTargetDependency */,
+ 40C8498C101A36A60083642A /* PBXTargetDependency */,
+ );
+ name = "sample1_unittest-static";
+ productName = sample1_unittest;
+ productReference = 40C84997101A36A60083642A /* sample1_unittest-static */;
+ productType = "com.apple.product-type.tool";
+ };
+ 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */;
+ buildPhases = (
+ 8D07F2C10486CC7A007CD1D0 /* Sources */,
+ 8D07F2BD0486CC7A007CD1D0 /* Headers */,
+ 404884A50E2F7C0400CF7658 /* Copy Headers Internal */,
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */,
+ 444D117214A2628F009FEC3F /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 40C44AE60E379922008FCC51 /* PBXTargetDependency */,
+ 408BEC101046CFE900DEF522 /* PBXTargetDependency */,
+ 40C8499C101A36DC0083642A /* PBXTargetDependency */,
+ );
+ name = "gtest-framework";
+ productInstallPath = "$(HOME)/Library/Frameworks";
+ productName = gtest;
+ productReference = 4539C8FF0EC27F6400A70F4C /* gtest.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 0867D690FE84028FC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */;
+ compatibilityVersion = "Xcode 2.4";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ en,
+ );
+ mainGroup = 0867D691FE84028FC02AAC07 /* gtest */;
+ productRefGroup = 034768DDFF38A45A11DB9C8B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */,
+ 40C848F9101A209C0083642A /* gtest-static */,
+ 40C8490A101A217E0083642A /* gtest_main-static */,
+ 40899F420FFA7184000B29AE /* gtest_unittest-framework */,
+ 40C8497A101A36850083642A /* gtest_unittest-static */,
+ 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */,
+ 40C84989101A36A60083642A /* sample1_unittest-static */,
+ 3B238F5F0E828B5400846E11 /* Check */,
+ 40C44ADC0E3798F4008FCC51 /* Version Info */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D07F2BF0486CC7A007CD1D0 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 404884500E2F799B00CF7658 /* README in Resources */,
+ 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */,
+ 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */,
+ 404884AE0E2F7CD900CF7658 /* COPYING in Resources */,
+ 40C84978101A36540083642A /* libgtest_main.a in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 3B238F5E0E828B5400846E11 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/bin/bash Scripts/runtests.sh";
+ };
+ 40C44ADB0E3798F4008FCC51 /* Generate Version.h */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/Scripts/versiongenerate.py",
+ "$(SRCROOT)/../configure.ac",
+ );
+ name = "Generate Version.h";
+ outputPaths = (
+ "$(PROJECT_TEMP_DIR)/Version.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "# Remember, this \"Run Script\" build phase will be executed from $SRCROOT\n/usr/bin/python Scripts/versiongenerate.py ../ $PROJECT_TEMP_DIR";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 40899F400FFA7184000B29AE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40899F530FFA72A0000B29AE /* gtest_unittest.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4089A0100FFACEFC000B29AE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4089A0440FFAD1BE000B29AE /* sample1.cc in Sources */,
+ 4089A0460FFAD1BE000B29AE /* sample1_unittest.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C848F7101A209C0083642A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C848FF101A21150083642A /* gtest-all.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C84908101A217E0083642A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C84915101A21DF0083642A /* gtest_main.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C8497F101A36850083642A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C84980101A36850083642A /* gtest_unittest.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 40C8498E101A36A60083642A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40C8498F101A36A60083642A /* sample1.cc in Sources */,
+ 40C84990101A36A60083642A /* sample1_unittest.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D07F2C10486CC7A007CD1D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 40899F3A0FFA70D4000B29AE /* gtest-all.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 40899F9D0FFA740F000B29AE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40899F420FFA7184000B29AE /* gtest_unittest-framework */;
+ targetProxy = 40899F9C0FFA740F000B29AE /* PBXContainerItemProxy */;
+ };
+ 4089A0980FFAD34A000B29AE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4089A0120FFACEFC000B29AE /* sample1_unittest-framework */;
+ targetProxy = 4089A0970FFAD34A000B29AE /* PBXContainerItemProxy */;
+ };
+ 408BEC101046CFE900DEF522 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C848F9101A209C0083642A /* gtest-static */;
+ targetProxy = 408BEC0F1046CFE900DEF522 /* PBXContainerItemProxy */;
+ };
+ 40C44AE60E379922008FCC51 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C44ADC0E3798F4008FCC51 /* Version Info */;
+ targetProxy = 40C44AE50E379922008FCC51 /* PBXContainerItemProxy */;
+ };
+ 40C8497B101A36850083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C848F9101A209C0083642A /* gtest-static */;
+ targetProxy = 40C8497C101A36850083642A /* PBXContainerItemProxy */;
+ };
+ 40C8497D101A36850083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C8490A101A217E0083642A /* gtest_main-static */;
+ targetProxy = 40C8497E101A36850083642A /* PBXContainerItemProxy */;
+ };
+ 40C8498A101A36A60083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C848F9101A209C0083642A /* gtest-static */;
+ targetProxy = 40C8498B101A36A60083642A /* PBXContainerItemProxy */;
+ };
+ 40C8498C101A36A60083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C8490A101A217E0083642A /* gtest_main-static */;
+ targetProxy = 40C8498D101A36A60083642A /* PBXContainerItemProxy */;
+ };
+ 40C8499C101A36DC0083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C8490A101A217E0083642A /* gtest_main-static */;
+ targetProxy = 40C8499B101A36DC0083642A /* PBXContainerItemProxy */;
+ };
+ 40C8499E101A36E50083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */;
+ targetProxy = 40C8499D101A36E50083642A /* PBXContainerItemProxy */;
+ };
+ 40C849A0101A36F10083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8D07F2BC0486CC7A007CD1D0 /* gtest-framework */;
+ targetProxy = 40C8499F101A36F10083642A /* PBXContainerItemProxy */;
+ };
+ 40C849F7101A43440083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C8497A101A36850083642A /* gtest_unittest-static */;
+ targetProxy = 40C849F6101A43440083642A /* PBXContainerItemProxy */;
+ };
+ 40C849F9101A43490083642A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 40C84989101A36A60083642A /* sample1_unittest-static */;
+ targetProxy = 40C849F8101A43490083642A /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 3B238F600E828B5400846E11 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = Check;
+ };
+ name = Debug;
+ };
+ 3B238F610E828B5400846E11 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = Check;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 40899F450FFA7185000B29AE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "gtest_unittest-framework";
+ };
+ name = Debug;
+ };
+ 40899F460FFA7185000B29AE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "gtest_unittest-framework";
+ };
+ name = Release;
+ };
+ 4089A0150FFACEFD000B29AE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-framework";
+ };
+ name = Debug;
+ };
+ 4089A0160FFACEFD000B29AE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-framework";
+ };
+ name = Release;
+ };
+ 40C44ADF0E3798F4008FCC51 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = gtest;
+ TARGET_NAME = gtest;
+ };
+ name = Debug;
+ };
+ 40C44AE00E3798F4008FCC51 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = gtest;
+ TARGET_NAME = gtest;
+ };
+ name = Release;
+ };
+ 40C848FB101A209D0083642A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ PRODUCT_NAME = gtest;
+ };
+ name = Debug;
+ };
+ 40C848FC101A209D0083642A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ PRODUCT_NAME = gtest;
+ };
+ name = Release;
+ };
+ 40C8490E101A217F0083642A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = gtest_main;
+ };
+ name = Debug;
+ };
+ 40C8490F101A217F0083642A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = gtest_main;
+ };
+ name = Release;
+ };
+ 40C84985101A36850083642A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = gtest_unittest;
+ };
+ name = Debug;
+ };
+ 40C84986101A36850083642A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = gtest_unittest;
+ };
+ name = Release;
+ };
+ 40C84995101A36A60083642A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-static";
+ };
+ name = Debug;
+ };
+ 40C84996101A36A60083642A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-static";
+ };
+ name = Release;
+ };
+ 44C48E0414A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 44C48DFF14A4098F00A2D9C7 /* ProductionProject.xcconfig */;
+ buildSettings = {
+ };
+ name = Production;
+ };
+ 44C48E0514A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ INFOPLIST_FILE = Resources/Info.plist;
+ INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h";
+ INFOPLIST_PREPROCESS = YES;
+ PRODUCT_NAME = gtest;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Production;
+ };
+ 44C48E0614A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ PRODUCT_NAME = gtest;
+ };
+ name = Production;
+ };
+ 44C48E0714A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */;
+ buildSettings = {
+ PRODUCT_NAME = gtest_main;
+ };
+ name = Production;
+ };
+ 44C48E0814A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "gtest_unittest-framework";
+ };
+ name = Production;
+ };
+ 44C48E0914A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = gtest_unittest;
+ };
+ name = Production;
+ };
+ 44C48E0A14A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-framework";
+ };
+ name = Production;
+ };
+ 44C48E0B14A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "sample1_unittest-static";
+ };
+ name = Production;
+ };
+ 44C48E0C14A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = Check;
+ ZERO_LINK = NO;
+ };
+ name = Production;
+ };
+ 44C48E0D14A409DE00A2D9C7 /* Production */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = gtest;
+ TARGET_NAME = gtest;
+ };
+ name = Production;
+ };
+ 4FADC24308B4156D00ABE55E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ INFOPLIST_FILE = Resources/Info.plist;
+ INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h";
+ INFOPLIST_PREPROCESS = YES;
+ PRODUCT_NAME = gtest;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 4FADC24408B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */;
+ buildSettings = {
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ INFOPLIST_FILE = Resources/Info.plist;
+ INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h";
+ INFOPLIST_PREPROCESS = YES;
+ PRODUCT_NAME = gtest;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+ 4FADC24708B4156D00ABE55E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF10E30E07400294801 /* DebugProject.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ 4FADC24808B4156D00ABE55E /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 3B238FA30E828BB600846E11 /* Build configuration list for PBXAggregateTarget "Check" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 3B238F600E828B5400846E11 /* Debug */,
+ 3B238F610E828B5400846E11 /* Release */,
+ 44C48E0C14A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40899F450FFA7185000B29AE /* Debug */,
+ 40899F460FFA7185000B29AE /* Release */,
+ 44C48E0814A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4089A0150FFACEFD000B29AE /* Debug */,
+ 4089A0160FFACEFD000B29AE /* Release */,
+ 44C48E0A14A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C44ADF0E3798F4008FCC51 /* Debug */,
+ 40C44AE00E3798F4008FCC51 /* Release */,
+ 44C48E0D14A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C848FB101A209D0083642A /* Debug */,
+ 40C848FC101A209D0083642A /* Release */,
+ 44C48E0614A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C8490E101A217F0083642A /* Debug */,
+ 40C8490F101A217F0083642A /* Release */,
+ 44C48E0714A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C84985101A36850083642A /* Debug */,
+ 40C84986101A36850083642A /* Release */,
+ 44C48E0914A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 40C84995101A36A60083642A /* Debug */,
+ 40C84996101A36A60083642A /* Release */,
+ 44C48E0B14A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24308B4156D00ABE55E /* Debug */,
+ 4FADC24408B4156D00ABE55E /* Release */,
+ 44C48E0514A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+ 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4FADC24708B4156D00ABE55E /* Debug */,
+ 4FADC24808B4156D00ABE55E /* Release */,
+ 44C48E0414A409DE00A2D9C7 /* Production */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Production;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
+}
diff --git a/Source/ThirdParty/gyp/AUTHORS b/Source/ThirdParty/gyp/AUTHORS
new file mode 100644
index 000000000..f0b6752ad
--- /dev/null
+++ b/Source/ThirdParty/gyp/AUTHORS
@@ -0,0 +1,5 @@
+# Names should be added to this file like so:
+# Name or Organization <email address>
+
+Google Inc.
+Steven Knight <knight@baldmt.com>
diff --git a/Source/ThirdParty/gyp/DEPS b/Source/ThirdParty/gyp/DEPS
new file mode 100644
index 000000000..0e56c063d
--- /dev/null
+++ b/Source/ThirdParty/gyp/DEPS
@@ -0,0 +1,8 @@
+# DEPS file for gclient use in buildbot execution of gyp tests.
+#
+# (You don't need to use gclient for normal GYP development work.)
+
+deps = {
+ "scons":
+ "http://src.chromium.org/svn/trunk/src/third_party/scons@44099",
+}
diff --git a/Source/ThirdParty/gyp/LICENSE b/Source/ThirdParty/gyp/LICENSE
new file mode 100644
index 000000000..ab6b011a1
--- /dev/null
+++ b/Source/ThirdParty/gyp/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Source/ThirdParty/gyp/MANIFEST b/Source/ThirdParty/gyp/MANIFEST
new file mode 100644
index 000000000..925ecc184
--- /dev/null
+++ b/Source/ThirdParty/gyp/MANIFEST
@@ -0,0 +1,21 @@
+setup.py
+gyp
+LICENSE
+AUTHORS
+pylib/gyp/MSVSNew.py
+pylib/gyp/MSVSProject.py
+pylib/gyp/MSVSToolFile.py
+pylib/gyp/MSVSUserFile.py
+pylib/gyp/MSVSVersion.py
+pylib/gyp/SCons.py
+pylib/gyp/__init__.py
+pylib/gyp/common.py
+pylib/gyp/input.py
+pylib/gyp/xcodeproj_file.py
+pylib/gyp/generator/__init__.py
+pylib/gyp/generator/gypd.py
+pylib/gyp/generator/gypsh.py
+pylib/gyp/generator/make.py
+pylib/gyp/generator/msvs.py
+pylib/gyp/generator/scons.py
+pylib/gyp/generator/xcode.py
diff --git a/Source/ThirdParty/gyp/PRESUBMIT.py b/Source/ThirdParty/gyp/PRESUBMIT.py
new file mode 100755
index 000000000..4c9928840
--- /dev/null
+++ b/Source/ThirdParty/gyp/PRESUBMIT.py
@@ -0,0 +1,53 @@
+# Copyright 2010, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+EXCLUDED_PATHS = ()
+
+
+def CheckChangeOnUpload(input_api, output_api):
+ report = []
+ black_list = input_api.DEFAULT_BLACK_LIST + EXCLUDED_PATHS
+ sources = lambda x: input_api.FilterSourceFile(x, black_list=black_list)
+ report.extend(input_api.canned_checks.CheckChangeSvnEolStyle(
+ input_api, output_api, sources))
+ return report
+
+
+def CheckChangeOnCommit(input_api, output_api):
+ report = []
+ black_list = input_api.DEFAULT_BLACK_LIST + EXCLUDED_PATHS
+ sources = lambda x: input_api.FilterSourceFile(x, black_list=black_list)
+ report.extend(input_api.canned_checks.CheckChangeSvnEolStyle(
+ input_api, output_api, sources))
+ report.extend(input_api.canned_checks.CheckTreeIsOpen(
+ input_api, output_api,
+ 'http://gyp-status.appspot.com/status',
+ 'http://gyp-status.appspot.com/current'))
+ return report
diff --git a/Source/ThirdParty/gyp/README.WebKit b/Source/ThirdParty/gyp/README.WebKit
new file mode 100644
index 000000000..9eed075d0
--- /dev/null
+++ b/Source/ThirdParty/gyp/README.WebKit
@@ -0,0 +1 @@
+This directory is a copy of http://gyp.googlecode.com/svn/trunk/ at revision 903.
diff --git a/Source/ThirdParty/gyp/codereview.settings b/Source/ThirdParty/gyp/codereview.settings
new file mode 100644
index 000000000..a04a2440d
--- /dev/null
+++ b/Source/ThirdParty/gyp/codereview.settings
@@ -0,0 +1,10 @@
+# This file is used by gcl to get repository specific information.
+CODE_REVIEW_SERVER: codereview.chromium.org
+CC_LIST: gyp-developer@googlegroups.com
+VIEW_VC: http://code.google.com/p/gyp/source/detail?r=
+TRY_ON_UPLOAD: True
+TRYSERVER_PROJECT: gyp
+TRYSERVER_PATCHLEVEL: 0
+TRYSERVER_ROOT: trunk
+TRYSERVER_SVN_URL: svn://svn.chromium.org/chrome-try/try-nacl
+
diff --git a/Source/ThirdParty/gyp/gyp b/Source/ThirdParty/gyp/gyp
new file mode 100755
index 000000000..d52e7116f
--- /dev/null
+++ b/Source/ThirdParty/gyp/gyp
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+# TODO(mark): sys.path manipulation is some temporary testing stuff.
+try:
+ import gyp
+except ImportError, e:
+ import os.path
+ sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'pylib'))
+ import gyp
+
+if __name__ == '__main__':
+ sys.exit(gyp.main(sys.argv[1:]))
diff --git a/Source/ThirdParty/gyp/gyp.bat b/Source/ThirdParty/gyp/gyp.bat
new file mode 100755
index 000000000..90fbc6d30
--- /dev/null
+++ b/Source/ThirdParty/gyp/gyp.bat
@@ -0,0 +1,5 @@
+@rem Copyright (c) 2009 Google Inc. All rights reserved.
+@rem Use of this source code is governed by a BSD-style license that can be
+@rem found in the LICENSE file.
+
+@python "%~dp0/gyp" %*
diff --git a/Source/ThirdParty/gyp/gyp_dummy.c b/Source/ThirdParty/gyp/gyp_dummy.c
new file mode 100644
index 000000000..fb55bbc78
--- /dev/null
+++ b/Source/ThirdParty/gyp/gyp_dummy.c
@@ -0,0 +1,7 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+int main() {
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/gyptest.py b/Source/ThirdParty/gyp/gyptest.py
new file mode 100755
index 000000000..d9677db3a
--- /dev/null
+++ b/Source/ThirdParty/gyp/gyptest.py
@@ -0,0 +1,255 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+__doc__ = """
+gyptest.py -- test runner for GYP tests.
+"""
+
+import os
+import optparse
+import subprocess
+import sys
+
+class CommandRunner:
+ """
+ Executor class for commands, including "commands" implemented by
+ Python functions.
+ """
+ verbose = True
+ active = True
+
+ def __init__(self, dictionary={}):
+ self.subst_dictionary(dictionary)
+
+ def subst_dictionary(self, dictionary):
+ self._subst_dictionary = dictionary
+
+ def subst(self, string, dictionary=None):
+ """
+ Substitutes (via the format operator) the values in the specified
+ dictionary into the specified command.
+
+ The command can be an (action, string) tuple. In all cases, we
+ perform substitution on strings and don't worry if something isn't
+ a string. (It's probably a Python function to be executed.)
+ """
+ if dictionary is None:
+ dictionary = self._subst_dictionary
+ if dictionary:
+ try:
+ string = string % dictionary
+ except TypeError:
+ pass
+ return string
+
+ def display(self, command, stdout=None, stderr=None):
+ if not self.verbose:
+ return
+ if type(command) == type(()):
+ func = command[0]
+ args = command[1:]
+ s = '%s(%s)' % (func.__name__, ', '.join(map(repr, args)))
+ if type(command) == type([]):
+ # TODO: quote arguments containing spaces
+ # TODO: handle meta characters?
+ s = ' '.join(command)
+ else:
+ s = self.subst(command)
+ if not s.endswith('\n'):
+ s += '\n'
+ sys.stdout.write(s)
+ sys.stdout.flush()
+
+ def execute(self, command, stdout=None, stderr=None):
+ """
+ Executes a single command.
+ """
+ if not self.active:
+ return 0
+ if type(command) == type(''):
+ command = self.subst(command)
+ cmdargs = shlex.split(command)
+ if cmdargs[0] == 'cd':
+ command = (os.chdir,) + tuple(cmdargs[1:])
+ if type(command) == type(()):
+ func = command[0]
+ args = command[1:]
+ return func(*args)
+ else:
+ if stdout is sys.stdout:
+ # Same as passing sys.stdout, except python2.4 doesn't fail on it.
+ subout = None
+ else:
+ # Open pipe for anything else so Popen works on python2.4.
+ subout = subprocess.PIPE
+ if stderr is sys.stderr:
+ # Same as passing sys.stderr, except python2.4 doesn't fail on it.
+ suberr = None
+ elif stderr is None:
+ # Merge with stdout if stderr isn't specified.
+ suberr = subprocess.STDOUT
+ else:
+ # Open pipe for anything else so Popen works on python2.4.
+ suberr = subprocess.PIPE
+ p = subprocess.Popen(command,
+ shell=(sys.platform == 'win32'),
+ stdout=subout,
+ stderr=suberr)
+ p.wait()
+ if stdout is None:
+ self.stdout = p.stdout.read()
+ elif stdout is not sys.stdout:
+ stdout.write(p.stdout.read())
+ if stderr not in (None, sys.stderr):
+ stderr.write(p.stderr.read())
+ return p.returncode
+
+ def run(self, command, display=None, stdout=None, stderr=None):
+ """
+ Runs a single command, displaying it first.
+ """
+ if display is None:
+ display = command
+ self.display(display)
+ return self.execute(command, stdout, stderr)
+
+
+class Unbuffered:
+ def __init__(self, fp):
+ self.fp = fp
+ def write(self, arg):
+ self.fp.write(arg)
+ self.fp.flush()
+ def __getattr__(self, attr):
+ return getattr(self.fp, attr)
+
+sys.stdout = Unbuffered(sys.stdout)
+sys.stderr = Unbuffered(sys.stderr)
+
+
+def find_all_gyptest_files(directory):
+ result = []
+ for root, dirs, files in os.walk(directory):
+ if '.svn' in dirs:
+ dirs.remove('.svn')
+ result.extend([ os.path.join(root, f) for f in files
+ if f.startswith('gyptest') and f.endswith('.py') ])
+ result.sort()
+ return result
+
+
+def main(argv=None):
+ if argv is None:
+ argv = sys.argv
+
+ usage = "gyptest.py [-ahlnq] [-f formats] [test ...]"
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option("-a", "--all", action="store_true",
+ help="run all tests")
+ parser.add_option("-C", "--chdir", action="store", default=None,
+ help="chdir to the specified directory")
+ parser.add_option("-f", "--format", action="store", default='',
+ help="run tests with the specified formats")
+ parser.add_option("-l", "--list", action="store_true",
+ help="list available tests and exit")
+ parser.add_option("-n", "--no-exec", action="store_true",
+ help="no execute, just print the command line")
+ parser.add_option("--passed", action="store_true",
+ help="report passed tests")
+ parser.add_option("--path", action="append", default=[],
+ help="additional $PATH directory")
+ parser.add_option("-q", "--quiet", action="store_true",
+ help="quiet, don't print test command lines")
+ opts, args = parser.parse_args(argv[1:])
+
+ if opts.chdir:
+ os.chdir(opts.chdir)
+
+ if opts.path:
+ os.environ['PATH'] += ':' + ':'.join(opts.path)
+
+ if not args:
+ if not opts.all:
+ sys.stderr.write('Specify -a to get all tests.\n')
+ return 1
+ args = ['test']
+
+ tests = []
+ for arg in args:
+ if os.path.isdir(arg):
+ tests.extend(find_all_gyptest_files(os.path.normpath(arg)))
+ else:
+ tests.append(arg)
+
+ if opts.list:
+ for test in tests:
+ print test
+ sys.exit(0)
+
+ CommandRunner.verbose = not opts.quiet
+ CommandRunner.active = not opts.no_exec
+ cr = CommandRunner()
+
+ os.environ['PYTHONPATH'] = os.path.abspath('test/lib')
+ if not opts.quiet:
+ sys.stdout.write('PYTHONPATH=%s\n' % os.environ['PYTHONPATH'])
+
+ passed = []
+ failed = []
+ no_result = []
+
+ if opts.format:
+ format_list = opts.format.split(',')
+ else:
+ # TODO: not duplicate this mapping from pylib/gyp/__init__.py
+ format_list = [ {
+ 'freebsd7': 'make',
+ 'freebsd8': 'make',
+ 'cygwin': 'msvs',
+ 'win32': 'msvs',
+ 'linux2': 'make',
+ 'darwin': 'xcode',
+ }[sys.platform] ]
+
+ for format in format_list:
+ os.environ['TESTGYP_FORMAT'] = format
+ if not opts.quiet:
+ sys.stdout.write('TESTGYP_FORMAT=%s\n' % format)
+
+ for test in tests:
+ status = cr.run([sys.executable, test],
+ stdout=sys.stdout,
+ stderr=sys.stderr)
+ if status == 2:
+ no_result.append(test)
+ elif status:
+ failed.append(test)
+ else:
+ passed.append(test)
+
+ if not opts.quiet:
+ def report(description, tests):
+ if tests:
+ if len(tests) == 1:
+ sys.stdout.write("\n%s the following test:\n" % description)
+ else:
+ fmt = "\n%s the following %d tests:\n"
+ sys.stdout.write(fmt % (description, len(tests)))
+ sys.stdout.write("\t" + "\n\t".join(tests) + "\n")
+
+ if opts.passed:
+ report("Passed", passed)
+ report("Failed", failed)
+ report("No result from", no_result)
+
+ if failed:
+ return 1
+ else:
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/Source/ThirdParty/gyp/pylib/gyp/MSVSNew.py b/Source/ThirdParty/gyp/pylib/gyp/MSVSNew.py
new file mode 100644
index 000000000..1277d4a50
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/MSVSNew.py
@@ -0,0 +1,341 @@
+#!/usr/bin/python2.4
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""New implementation of Visual Studio project generation for SCons."""
+
+import common
+import os
+import random
+
+import gyp.common
+
+# hashlib is supplied as of Python 2.5 as the replacement interface for md5
+# and other secure hashes. In 2.6, md5 is deprecated. Import hashlib if
+# available, avoiding a deprecation warning under 2.6. Import md5 otherwise,
+# preserving 2.4 compatibility.
+try:
+ import hashlib
+ _new_md5 = hashlib.md5
+except ImportError:
+ import md5
+ _new_md5 = md5.new
+
+
+# Initialize random number generator
+random.seed()
+
+# GUIDs for project types
+ENTRY_TYPE_GUIDS = {
+ 'project': '{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}',
+ 'folder': '{2150E333-8FDC-42A3-9474-1A3956D46DE8}',
+}
+
+#------------------------------------------------------------------------------
+# Helper functions
+
+
+def MakeGuid(name, seed='msvs_new'):
+ """Returns a GUID for the specified target name.
+
+ Args:
+ name: Target name.
+ seed: Seed for MD5 hash.
+ Returns:
+ A GUID-line string calculated from the name and seed.
+
+ This generates something which looks like a GUID, but depends only on the
+ name and seed. This means the same name/seed will always generate the same
+ GUID, so that projects and solutions which refer to each other can explicitly
+ determine the GUID to refer to explicitly. It also means that the GUID will
+ not change when the project for a target is rebuilt.
+ """
+ # Calculate a MD5 signature for the seed and name.
+ d = _new_md5(str(seed) + str(name)).hexdigest().upper()
+ # Convert most of the signature to GUID form (discard the rest)
+ guid = ('{' + d[:8] + '-' + d[8:12] + '-' + d[12:16] + '-' + d[16:20]
+ + '-' + d[20:32] + '}')
+ return guid
+
+#------------------------------------------------------------------------------
+
+
+class MSVSFolder:
+ """Folder in a Visual Studio project or solution."""
+
+ def __init__(self, path, name = None, entries = None,
+ guid = None, items = None):
+ """Initializes the folder.
+
+ Args:
+ path: Full path to the folder.
+ name: Name of the folder.
+ entries: List of folder entries to nest inside this folder. May contain
+ Folder or Project objects. May be None, if the folder is empty.
+ guid: GUID to use for folder, if not None.
+ items: List of solution items to include in the folder project. May be
+ None, if the folder does not directly contain items.
+ """
+ if name:
+ self.name = name
+ else:
+ # Use last layer.
+ self.name = os.path.basename(path)
+
+ self.path = path
+ self.guid = guid
+
+ # Copy passed lists (or set to empty lists)
+ self.entries = list(entries or [])
+ self.items = list(items or [])
+
+ self.entry_type_guid = ENTRY_TYPE_GUIDS['folder']
+
+ def get_guid(self):
+ if self.guid is None:
+ # Use consistent guids for folders (so things don't regenerate).
+ self.guid = MakeGuid(self.path, seed='msvs_folder')
+ return self.guid
+
+
+#------------------------------------------------------------------------------
+
+
+class MSVSProject:
+ """Visual Studio project."""
+
+ def __init__(self, path, name = None, dependencies = None, guid = None,
+ spec = None, build_file = None, config_platform_overrides = None,
+ fixpath_prefix = None):
+ """Initializes the project.
+
+ Args:
+ path: Absolute path to the project file.
+ name: Name of project. If None, the name will be the same as the base
+ name of the project file.
+ dependencies: List of other Project objects this project is dependent
+ upon, if not None.
+ guid: GUID to use for project, if not None.
+ spec: Dictionary specifying how to build this project.
+ build_file: Filename of the .gyp file that the vcproj file comes from.
+ config_platform_overrides: optional dict of configuration platforms to
+ used in place of the default for this target.
+ fixpath_prefix: the path used to adjust the behavior of _fixpath
+ """
+ self.path = path
+ self.guid = guid
+ self.spec = spec
+ self.build_file = build_file
+ # Use project filename if name not specified
+ self.name = name or os.path.splitext(os.path.basename(path))[0]
+
+ # Copy passed lists (or set to empty lists)
+ self.dependencies = list(dependencies or [])
+
+ self.entry_type_guid = ENTRY_TYPE_GUIDS['project']
+
+ if config_platform_overrides:
+ self.config_platform_overrides = config_platform_overrides
+ else:
+ self.config_platform_overrides = {}
+ self.fixpath_prefix = fixpath_prefix
+
+ def set_dependencies(self, dependencies):
+ self.dependencies = list(dependencies or [])
+
+ def get_guid(self):
+ if self.guid is None:
+ # Set GUID from path
+ # TODO(rspangler): This is fragile.
+ # 1. We can't just use the project filename sans path, since there could
+ # be multiple projects with the same base name (for example,
+ # foo/unittest.vcproj and bar/unittest.vcproj).
+ # 2. The path needs to be relative to $SOURCE_ROOT, so that the project
+ # GUID is the same whether it's included from base/base.sln or
+ # foo/bar/baz/baz.sln.
+ # 3. The GUID needs to be the same each time this builder is invoked, so
+ # that we don't need to rebuild the solution when the project changes.
+ # 4. We should be able to handle pre-built project files by reading the
+ # GUID from the files.
+ self.guid = MakeGuid(self.name)
+ return self.guid
+
+#------------------------------------------------------------------------------
+
+
+class MSVSSolution:
+ """Visual Studio solution."""
+
+ def __init__(self, path, version, entries=None, variants=None,
+ websiteProperties=True):
+ """Initializes the solution.
+
+ Args:
+ path: Path to solution file.
+ version: Format version to emit.
+ entries: List of entries in solution. May contain Folder or Project
+ objects. May be None, if the folder is empty.
+ variants: List of build variant strings. If none, a default list will
+ be used.
+ websiteProperties: Flag to decide if the website properties section
+ is generated.
+ """
+ self.path = path
+ self.websiteProperties = websiteProperties
+ self.version = version
+
+ # Copy passed lists (or set to empty lists)
+ self.entries = list(entries or [])
+
+ if variants:
+ # Copy passed list
+ self.variants = variants[:]
+ else:
+ # Use default
+ self.variants = ['Debug|Win32', 'Release|Win32']
+ # TODO(rspangler): Need to be able to handle a mapping of solution config
+ # to project config. Should we be able to handle variants being a dict,
+ # or add a separate variant_map variable? If it's a dict, we can't
+ # guarantee the order of variants since dict keys aren't ordered.
+
+
+ # TODO(rspangler): Automatically write to disk for now; should delay until
+ # node-evaluation time.
+ self.Write()
+
+
+ def Write(self, writer=common.WriteOnDiff):
+ """Writes the solution file to disk.
+
+ Raises:
+ IndexError: An entry appears multiple times.
+ """
+ # Walk the entry tree and collect all the folders and projects.
+ all_entries = []
+ entries_to_check = self.entries[:]
+ while entries_to_check:
+ # Pop from the beginning of the list to preserve the user's order.
+ e = entries_to_check.pop(0)
+
+ # A project or folder can only appear once in the solution's folder tree.
+ # This also protects from cycles.
+ if e in all_entries:
+ #raise IndexError('Entry "%s" appears more than once in solution' %
+ # e.name)
+ continue
+
+ all_entries.append(e)
+
+ # If this is a folder, check its entries too.
+ if isinstance(e, MSVSFolder):
+ entries_to_check += e.entries
+
+ # Sort by name then guid (so things are in order on vs2008).
+ def NameThenGuid(a, b):
+ if a.name < b.name: return -1
+ if a.name > b.name: return 1
+ if a.get_guid() < b.get_guid(): return -1
+ if a.get_guid() > b.get_guid(): return 1
+ return 0
+
+ all_entries = sorted(all_entries, NameThenGuid)
+
+ # Open file and print header
+ f = writer(self.path)
+ f.write('Microsoft Visual Studio Solution File, '
+ 'Format Version %s\r\n' % self.version.SolutionVersion())
+ f.write('# %s\r\n' % self.version.Description())
+
+ # Project entries
+ sln_root = os.path.split(self.path)[0]
+ for e in all_entries:
+ relative_path = gyp.common.RelativePath(e.path, sln_root)
+ f.write('Project("%s") = "%s", "%s", "%s"\r\n' % (
+ e.entry_type_guid, # Entry type GUID
+ e.name, # Folder name
+ relative_path.replace('/', '\\'), # Folder name (again)
+ e.get_guid(), # Entry GUID
+ ))
+
+ # TODO(rspangler): Need a way to configure this stuff
+ if self.websiteProperties:
+ f.write('\tProjectSection(WebsiteProperties) = preProject\r\n'
+ '\t\tDebug.AspNetCompiler.Debug = "True"\r\n'
+ '\t\tRelease.AspNetCompiler.Debug = "False"\r\n'
+ '\tEndProjectSection\r\n')
+
+ if isinstance(e, MSVSFolder):
+ if e.items:
+ f.write('\tProjectSection(SolutionItems) = preProject\r\n')
+ for i in e.items:
+ f.write('\t\t%s = %s\r\n' % (i, i))
+ f.write('\tEndProjectSection\r\n')
+
+ if isinstance(e, MSVSProject):
+ if e.dependencies:
+ f.write('\tProjectSection(ProjectDependencies) = postProject\r\n')
+ for d in e.dependencies:
+ f.write('\t\t%s = %s\r\n' % (d.get_guid(), d.get_guid()))
+ f.write('\tEndProjectSection\r\n')
+
+ f.write('EndProject\r\n')
+
+ # Global section
+ f.write('Global\r\n')
+
+ # Configurations (variants)
+ f.write('\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\r\n')
+ for v in self.variants:
+ f.write('\t\t%s = %s\r\n' % (v, v))
+ f.write('\tEndGlobalSection\r\n')
+
+ # Sort config guids for easier diffing of solution changes.
+ config_guids = []
+ config_guids_overrides = {}
+ for e in all_entries:
+ if isinstance(e, MSVSProject):
+ config_guids.append(e.get_guid())
+ config_guids_overrides[e.get_guid()] = e.config_platform_overrides
+ config_guids.sort()
+
+ f.write('\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\r\n')
+ for g in config_guids:
+ for v in self.variants:
+ nv = config_guids_overrides[g].get(v, v)
+ # Pick which project configuration to build for this solution
+ # configuration.
+ f.write('\t\t%s.%s.ActiveCfg = %s\r\n' % (
+ g, # Project GUID
+ v, # Solution build configuration
+ nv, # Project build config for that solution config
+ ))
+
+ # Enable project in this solution configuration.
+ f.write('\t\t%s.%s.Build.0 = %s\r\n' % (
+ g, # Project GUID
+ v, # Solution build configuration
+ nv, # Project build config for that solution config
+ ))
+ f.write('\tEndGlobalSection\r\n')
+
+ # TODO(rspangler): Should be able to configure this stuff too (though I've
+ # never seen this be any different)
+ f.write('\tGlobalSection(SolutionProperties) = preSolution\r\n')
+ f.write('\t\tHideSolutionNode = FALSE\r\n')
+ f.write('\tEndGlobalSection\r\n')
+
+ # Folder mappings
+ # TODO(rspangler): Should omit this section if there are no folders
+ f.write('\tGlobalSection(NestedProjects) = preSolution\r\n')
+ for e in all_entries:
+ if not isinstance(e, MSVSFolder):
+ continue # Does not apply to projects, only folders
+ for subentry in e.entries:
+ f.write('\t\t%s = %s\r\n' % (subentry.get_guid(), e.get_guid()))
+ f.write('\tEndGlobalSection\r\n')
+
+ f.write('EndGlobal\r\n')
+
+ f.close()
diff --git a/Source/ThirdParty/gyp/pylib/gyp/MSVSProject.py b/Source/ThirdParty/gyp/pylib/gyp/MSVSProject.py
new file mode 100644
index 000000000..1246fdd9c
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/MSVSProject.py
@@ -0,0 +1,245 @@
+#!/usr/bin/python2.4
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Visual Studio project reader/writer."""
+
+import common
+import xml.dom
+import xml_fix
+
+#------------------------------------------------------------------------------
+
+
+class Tool(object):
+ """Visual Studio tool."""
+
+ def __init__(self, name, attrs=None):
+ """Initializes the tool.
+
+ Args:
+ name: Tool name.
+ attrs: Dict of tool attributes; may be None.
+ """
+ self.name = name
+ self.attrs = attrs or {}
+
+ def CreateElement(self, doc):
+ """Creates an element for the tool.
+
+ Args:
+ doc: xml.dom.Document object to use for node creation.
+
+ Returns:
+ A new xml.dom.Element for the tool.
+ """
+ node = doc.createElement('Tool')
+ node.setAttribute('Name', self.name)
+ for k, v in self.attrs.items():
+ node.setAttribute(k, v)
+ return node
+
+
+class Filter(object):
+ """Visual Studio filter - that is, a virtual folder."""
+
+ def __init__(self, name, contents=None):
+ """Initializes the folder.
+
+ Args:
+ name: Filter (folder) name.
+ contents: List of filenames and/or Filter objects contained.
+ """
+ self.name = name
+ self.contents = list(contents or [])
+
+
+#------------------------------------------------------------------------------
+
+
+class Writer(object):
+ """Visual Studio XML project writer."""
+
+ def __init__(self, project_path, version):
+ """Initializes the project.
+
+ Args:
+ project_path: Path to the project file.
+ version: Format version to emit.
+ """
+ self.project_path = project_path
+ self.doc = None
+ self.version = version
+
+ def Create(self, name, guid=None, platforms=None):
+ """Creates the project document.
+
+ Args:
+ name: Name of the project.
+ guid: GUID to use for project, if not None.
+ """
+ self.name = name
+ self.guid = guid
+
+ # Default to Win32 for platforms.
+ if not platforms:
+ platforms = ['Win32']
+
+ # Create XML doc
+ xml_impl = xml.dom.getDOMImplementation()
+ self.doc = xml_impl.createDocument(None, 'VisualStudioProject', None)
+
+ # Add attributes to root element
+ self.n_root = self.doc.documentElement
+ self.n_root.setAttribute('ProjectType', 'Visual C++')
+ self.n_root.setAttribute('Version', self.version.ProjectVersion())
+ self.n_root.setAttribute('Name', self.name)
+ self.n_root.setAttribute('ProjectGUID', self.guid)
+ self.n_root.setAttribute('RootNamespace', self.name)
+ self.n_root.setAttribute('Keyword', 'Win32Proj')
+
+ # Add platform list
+ n_platform = self.doc.createElement('Platforms')
+ self.n_root.appendChild(n_platform)
+ for platform in platforms:
+ n = self.doc.createElement('Platform')
+ n.setAttribute('Name', platform)
+ n_platform.appendChild(n)
+
+ # Add tool files section
+ self.n_tool_files = self.doc.createElement('ToolFiles')
+ self.n_root.appendChild(self.n_tool_files)
+
+ # Add configurations section
+ self.n_configs = self.doc.createElement('Configurations')
+ self.n_root.appendChild(self.n_configs)
+
+ # Add empty References section
+ self.n_root.appendChild(self.doc.createElement('References'))
+
+ # Add files section
+ self.n_files = self.doc.createElement('Files')
+ self.n_root.appendChild(self.n_files)
+ # Keep a dict keyed on filename to speed up access.
+ self.n_files_dict = dict()
+
+ # Add empty Globals section
+ self.n_root.appendChild(self.doc.createElement('Globals'))
+
+ def AddToolFile(self, path):
+ """Adds a tool file to the project.
+
+ Args:
+ path: Relative path from project to tool file.
+ """
+ n_tool = self.doc.createElement('ToolFile')
+ n_tool.setAttribute('RelativePath', path)
+ self.n_tool_files.appendChild(n_tool)
+
+ def _AddConfigToNode(self, parent, config_type, config_name, attrs=None,
+ tools=None):
+ """Adds a configuration to the parent node.
+
+ Args:
+ parent: Destination node.
+ config_type: Type of configuration node.
+ config_name: Configuration name.
+ attrs: Dict of configuration attributes; may be None.
+ tools: List of tools (strings or Tool objects); may be None.
+ """
+ # Handle defaults
+ if not attrs:
+ attrs = {}
+ if not tools:
+ tools = []
+
+ # Add configuration node and its attributes
+ n_config = self.doc.createElement(config_type)
+ n_config.setAttribute('Name', config_name)
+ for k, v in attrs.items():
+ n_config.setAttribute(k, v)
+ parent.appendChild(n_config)
+
+ # Add tool nodes and their attributes
+ if tools:
+ for t in tools:
+ if isinstance(t, Tool):
+ n_config.appendChild(t.CreateElement(self.doc))
+ else:
+ n_config.appendChild(Tool(t).CreateElement(self.doc))
+
+ def AddConfig(self, name, attrs=None, tools=None):
+ """Adds a configuration to the project.
+
+ Args:
+ name: Configuration name.
+ attrs: Dict of configuration attributes; may be None.
+ tools: List of tools (strings or Tool objects); may be None.
+ """
+ self._AddConfigToNode(self.n_configs, 'Configuration', name, attrs, tools)
+
+ def _AddFilesToNode(self, parent, files):
+ """Adds files and/or filters to the parent node.
+
+ Args:
+ parent: Destination node
+ files: A list of Filter objects and/or relative paths to files.
+
+ Will call itself recursively, if the files list contains Filter objects.
+ """
+ for f in files:
+ if isinstance(f, Filter):
+ node = self.doc.createElement('Filter')
+ node.setAttribute('Name', f.name)
+ self._AddFilesToNode(node, f.contents)
+ else:
+ node = self.doc.createElement('File')
+ node.setAttribute('RelativePath', f)
+ self.n_files_dict[f] = node
+ parent.appendChild(node)
+
+ def AddFiles(self, files):
+ """Adds files to the project.
+
+ Args:
+ files: A list of Filter objects and/or relative paths to files.
+
+ This makes a copy of the file/filter tree at the time of this call. If you
+ later add files to a Filter object which was passed into a previous call
+ to AddFiles(), it will not be reflected in this project.
+ """
+ self._AddFilesToNode(self.n_files, files)
+ # TODO(rspangler) This also doesn't handle adding files to an existing
+ # filter. That is, it doesn't merge the trees.
+
+ def AddFileConfig(self, path, config, attrs=None, tools=None):
+ """Adds a configuration to a file.
+
+ Args:
+ path: Relative path to the file.
+ config: Name of configuration to add.
+ attrs: Dict of configuration attributes; may be None.
+ tools: List of tools (strings or Tool objects); may be None.
+
+ Raises:
+ ValueError: Relative path does not match any file added via AddFiles().
+ """
+ # Find the file node with the right relative path
+ parent = self.n_files_dict.get(path)
+ if not parent:
+ raise ValueError('AddFileConfig: file "%s" not in project.' % path)
+
+ # Add the config to the file node
+ self._AddConfigToNode(parent, 'FileConfiguration', config, attrs, tools)
+
+ def Write(self, writer=common.WriteOnDiff):
+ """Writes the project file."""
+ f = writer(self.project_path)
+ fix = xml_fix.XmlFix()
+ self.doc.writexml(f, encoding='Windows-1252', addindent=' ', newl='\r\n')
+ fix.Cleanup()
+ f.close()
+
+#------------------------------------------------------------------------------
diff --git a/Source/ThirdParty/gyp/pylib/gyp/MSVSSettings.py b/Source/ThirdParty/gyp/pylib/gyp/MSVSSettings.py
new file mode 100644
index 000000000..5b79dd5cd
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/MSVSSettings.py
@@ -0,0 +1,980 @@
+#!/usr/bin/python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Code to validate and convert settings of the Microsoft build tools.
+
+This file contains code to validate and convert settings of the Microsoft
+build tools. The function ConvertToMsBuildSettings(), ValidateMSVSSettings(),
+and ValidateMSBuildSettings() are the entry points.
+
+This file was created by comparing the projects created by Visual Studio 2008
+and Visual Studio 2010 for all available settings through the user interface.
+The MSBuild schemas were also considered. They are typically found in the
+MSBuild install directory, e.g. c:\Program Files (x86)\MSBuild
+"""
+
+import sys
+
+
+# Dictionaries of settings validators. The key is the tool name, the value is
+# a dictionary mapping setting names to validation functions.
+_msvs_validators = {}
+_msbuild_validators = {}
+
+
+# A dictionary of settings converters. The key is the tool name, the value is
+# a dictionary mapping setting names to conversion functions.
+_msvs_to_msbuild_converters = {}
+
+
+# Tool name mapping from MSVS to MSBuild.
+_msbuild_name_of_tool = {}
+
+
+def _AddTool(names):
+ """ Adds a tool to the four dictionaries used to process settings.
+
+ This only defines the tool. Each setting also needs to be added.
+
+ Args:
+ names: a dictionary of the MSVS and MSBuild names of this tool.
+ """
+ msvs_name = names['msvs']
+ msbuild_name = names['msbuild']
+ _msvs_validators[msvs_name] = {}
+ _msbuild_validators[msbuild_name] = {}
+ _msvs_to_msbuild_converters[msvs_name] = {}
+ _msbuild_name_of_tool[msvs_name] = msbuild_name
+
+
+def _GetMsBuildToolSettings(msbuild_settings, tool):
+ """ Returns an MSBuild tool dictionary. Creates it if needed. """
+ tool_name = tool['msbuild']
+ return _GetOrCreateSubDictionary(msbuild_settings, tool_name)
+
+
+def _GetOrCreateSubDictionary(dict, name):
+ """ Returns or creates one of the sub-dictionary of dict. """
+ if not name in dict:
+ dict[name] = {}
+ return dict[name]
+
+
+class _Type:
+ """ Type of settings (Base class). """
+ def ValidateMSVS(self, value):
+ """ Raises ValueError if value is not valid for MSVS. """
+ pass
+ def ValidateMSBuild(self, value):
+ """ Raises ValueError if value is not valid for MSBuild. """
+ pass
+ def ConvertToMSBuild(self, value):
+ """ Returns the MSBuild equivalent of the MSVS value given.
+
+ Raises ValueError if value is not valid.
+ """
+ return value
+
+
+class _String(_Type):
+ """ A setting that's just a string. """
+ def ValidateMSVS(self, value):
+ if not isinstance(value, str):
+ raise ValueError
+ def ValidateMSBuild(self, value):
+ if not isinstance(value, str):
+ raise ValueError
+ def ConvertToMSBuild(self, value):
+ # Convert the macros
+ return _ConvertVCMacrosToMsBuild(value)
+
+
+class _StringList(_Type):
+ """ A settings that's a list of strings. """
+ def ValidateMSVS(self, value):
+ if not isinstance(value, str) and not isinstance(value, list):
+ raise ValueError
+ def ValidateMSBuild(self, value):
+ if not isinstance(value, str) and not isinstance(value, list):
+ raise ValueError
+ def ConvertToMSBuild(self, value):
+ # Convert the macros
+ if isinstance(value, list):
+ return [_ConvertVCMacrosToMsBuild(i) for i in value]
+ else:
+ return _ConvertVCMacrosToMsBuild(value)
+
+
+class _Boolean(_Type):
+ """ Boolean settings, can have the values 'false' or 'true'. """
+ def _Validate(self, value):
+ if value != 'true' and value != 'false':
+ raise ValueError
+ def ValidateMSVS(self, value):
+ self._Validate(value)
+ def ValidateMSBuild(self, value):
+ self._Validate(value)
+ def ConvertToMSBuild(self, value):
+ self._Validate(value)
+ return value
+
+
+class _Integer(_Type):
+ """ Integer settings. """
+ def __init__(self, msbuild_base=10):
+ self.msbuild_base = msbuild_base
+ def ValidateMSVS(self, value):
+ # Try to convert, this will raise ValueError if invalid.
+ self.ConvertToMSBuild(value)
+ def ValidateMSBuild(self, value):
+ # Try to convert, this will raise ValueError if invalid.
+ int(value, self.msbuild_base)
+ def ConvertToMSBuild(self, value):
+ format = (self.msbuild_base == 10) and '%d' or '0x%04x'
+ return format % int(value)
+
+
+class _Enumeration(_Type):
+ """ Type of settings that is an enumeration.
+
+ In MSVS, the values are indexes like '0', '1', and '2'.
+ MSBuild uses text labels that are more representative, like 'Win32'.
+
+ Constructor args:
+ label_list: an array of MSBuild labels that correspond to the MSVS index.
+ In the rare cases where MSVS has skipped an index value, None is
+ used in the array to indicate the unused spot.
+ new: an array of labels that are new to MSBuild.
+ """
+ def __init__(self, label_list, new=[]):
+ self.label_list = label_list
+ self.msbuild_values = set()
+ for value in label_list:
+ if not value is None:
+ self.msbuild_values.add(value)
+ for value in new:
+ self.msbuild_values.add(value)
+ def ValidateMSVS(self, value):
+ # Try to convert. It will raise an exception if not valid.
+ self.ConvertToMSBuild(value)
+ def ValidateMSBuild(self, value):
+ if not value in self.msbuild_values:
+ raise ValueError
+ def ConvertToMSBuild(self, value):
+ index = int(value)
+ if index < 0 or index >= len(self.label_list):
+ raise ValueError
+ label = self.label_list[index]
+ if label is None:
+ raise ValueError
+ return label
+
+
+# Instantiate the various generic types.
+_boolean = _Boolean()
+_integer = _Integer()
+# For now, we don't do any special validation on these types:
+_string = _String()
+_file_name = _String()
+_folder_name = _String()
+_file_list = _StringList()
+_folder_list = _StringList()
+_string_list = _StringList()
+# Some boolean settings went from numerical values to boolean. The
+# mapping is 0: default, 1: false, 2: true.
+_newly_boolean = _Enumeration(['', 'false', 'true'])
+
+
+def _Same(tool, name, type):
+ """ Defines a setting that has the same name in MSVS and MSBuild.
+
+ Args:
+ tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+ name: the name of the setting.
+ type: the type of this setting.
+ """
+ _Renamed(tool, name, name, type)
+
+
+def _Renamed(tool, msvs_name, msbuild_name, type):
+ """ Defines a setting for which the name has changed.
+
+ Args:
+ tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+ msvs_name: the name of the MSVS setting.
+ msbuild_name: the name of the MSBuild setting.
+ type: the type of this setting.
+ """
+ def _Translate(value, msbuild_settings):
+ msbuild_tool_settings = _GetMsBuildToolSettings(msbuild_settings, tool)
+ msbuild_tool_settings[msbuild_name] = type.ConvertToMSBuild(value)
+ msvs_tool_name = tool['msvs']
+ msbuild_tool_name = tool['msbuild']
+ _msvs_validators[msvs_tool_name][msvs_name] = type.ValidateMSVS
+ _msbuild_validators[msbuild_tool_name][msbuild_name] = type.ValidateMSBuild
+ _msvs_to_msbuild_converters[msvs_tool_name][msvs_name] = _Translate
+
+
+def _Moved(tool, settings_name, msbuild_tool_name, type):
+ _MovedAndRenamed(tool, settings_name, msbuild_tool_name, settings_name,
+ type)
+
+
+def _MovedAndRenamed(tool, msvs_settings_name, msbuild_tool_name,
+ msbuild_settings_name, type):
+ """ Defines a setting that may have moved to a new section.
+
+ Args:
+ tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+ msvs_settings_name: the MSVS name of the setting.
+ msbuild_tool_name: the name of the MSBuild tool to place the setting under.
+ msbuild_settings_name: the MSBuild name of the setting.
+ type: the type of this setting.
+ """
+ def _Translate(value, msbuild_settings):
+ tool_settings = _GetOrCreateSubDictionary(msbuild_settings,
+ msbuild_tool_name)
+ tool_settings[msbuild_settings_name] = type.ConvertToMSBuild(value)
+ msvs_tool_name = tool['msvs']
+ _msvs_validators[msvs_tool_name][msvs_settings_name] = type.ValidateMSVS
+ validator = type.ValidateMSBuild
+ _msbuild_validators[msbuild_tool_name][msbuild_settings_name] = validator
+ _msvs_to_msbuild_converters[msvs_tool_name][msvs_settings_name] = _Translate
+
+
+def _MSVSOnly(tool, name, type):
+ """ Defines a setting that is only found in MSVS.
+
+ Args:
+ tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+ name: the name of the setting.
+ type: the type of this setting.
+ """
+ def _Translate(value, msbuild_settings):
+ pass
+ msvs_tool_name = tool['msvs']
+ _msvs_validators[msvs_tool_name][name] = type.ValidateMSVS
+ _msvs_to_msbuild_converters[msvs_tool_name][name] = _Translate
+
+
+def _MSBuildOnly(tool, name, type):
+ """ Defines a setting that is only found in MSBuild.
+
+ Args:
+ tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+ name: the name of the setting.
+ type: the type of this setting.
+ """
+ msbuild_tool_name = tool['msbuild']
+ _msbuild_validators[msbuild_tool_name][name] = type.ValidateMSBuild
+
+
+def _ConvertedToAdditionalOption(tool, msvs_name, flag):
+ """ Defines a setting that's handled via a command line option in MSBuild.
+
+ Args:
+ tool: a dictionary that gives the names of the tool for MSVS and MSBuild.
+ msvs_name: the name of the MSVS setting that if 'true' becomes a flag
+ flag: the flag to insert at the end of the AdditionalOptions
+ """
+ def _Translate(value, msbuild_settings):
+ if value == 'true':
+ tool_settings = _GetMsBuildToolSettings(msbuild_settings, tool)
+ if 'AdditionalOptions' in tool_settings:
+ new_flags = "%s %s" % (tool_settings['AdditionalOptions'], flag)
+ else:
+ new_flags = flag
+ tool_settings['AdditionalOptions'] = new_flags
+ msvs_tool_name = tool['msvs']
+ _msvs_validators[msvs_tool_name][msvs_name] = _boolean.ValidateMSVS
+ _msvs_to_msbuild_converters[msvs_tool_name][msvs_name] = _Translate
+
+
+def _CustomGeneratePreprocessedFile(tool, msvs_name):
+ def _Translate(value, msbuild_settings):
+ tool_settings = _GetMsBuildToolSettings(msbuild_settings, tool)
+ if value == '0':
+ tool_settings['PreprocessToFile'] = 'false'
+ tool_settings['PreprocessSuppressLineNumbers'] = 'false'
+ elif value == '1': # /P
+ tool_settings['PreprocessToFile'] = 'true'
+ tool_settings['PreprocessSuppressLineNumbers'] = 'false'
+ elif value == '2': # /EP /P
+ tool_settings['PreprocessToFile'] = 'true'
+ tool_settings['PreprocessSuppressLineNumbers'] = 'true'
+ else:
+ raise ValueError
+ msvs_tool_name = tool['msvs']
+ # Create a bogus validator that looks for '0', '1', or '2'
+ msvs_validator = _Enumeration(['a', 'b', 'c']).ValidateMSVS
+ _msvs_validators[msvs_tool_name][msvs_name] = msvs_validator
+ msbuild_validator = _boolean.ValidateMSBuild
+ msbuild_tool_validators = _msbuild_validators[tool['msbuild']]
+ msbuild_tool_validators['PreprocessToFile'] = msbuild_validator
+ msbuild_tool_validators['PreprocessSuppressLineNumbers'] = msbuild_validator
+ _msvs_to_msbuild_converters[msvs_tool_name][msvs_name] = _Translate
+
+
+def _ConvertVCMacrosToMsBuild(s):
+ if (s.find('$') >= 0):
+ s = s.replace('$(ConfigurationName)', '$(Configuration)')
+ s = s.replace('$(InputDir)', '%(RootDir)%(Directory)')
+ s = s.replace('$(InputExt)', '%(Extension)')
+ s = s.replace('$(InputFileName)', '%(Filename)%(Extension)')
+ s = s.replace('$(InputName)', '%(Filename)')
+ s = s.replace('$(InputPath)', '%(FullPath)')
+ s = s.replace('$(ParentName)', '$(ProjectFileName)')
+ s = s.replace('$(PlatformName)', '$(Platform)')
+ s = s.replace('$(SafeInputName)', '%(Filename)')
+
+ s = s.replace('$(IntDir)\\', '$(IntDir)')
+ s = s.replace('$(OutDir)\\', '$(OutDir)')
+ s = s.replace('$(IntDir)/', '$(IntDir)')
+ s = s.replace('$(OutDir)/', '$(OutDir)')
+ return s
+
+
+def ConvertToMsBuildSettings(msvs_settings, stderr=sys.stderr):
+ """ Converts MSVS settings (VS2008 and earlier) to MSBuild settings (VS2010+).
+
+ Args:
+ msvs_settings: A dictionary. The key is the tool name. The values are
+ themselves dictionaries of settings and their values.
+ stderr: The stream receiving the error messages.
+ Returns:
+ A dictionary of MSBuild settings. The key is either the MSBuild tool name
+ or the empty string (for the global settings). The values are themselves
+ dictionaries of settings and their values.
+ """
+ msbuild_settings = {}
+ for msvs_tool_name, msvs_tool_settings in msvs_settings.iteritems():
+ if msvs_tool_name in _msvs_to_msbuild_converters:
+ msvs_tool = _msvs_to_msbuild_converters[msvs_tool_name]
+ for msvs_setting, msvs_value in msvs_tool_settings.iteritems():
+ if msvs_setting in msvs_tool:
+ # Invoke the translation function.
+ try:
+ msvs_tool[msvs_setting](msvs_value, msbuild_settings)
+ except ValueError:
+ print >> stderr, ('Warning: unrecognized value "%s" for %s/%s '
+ 'while converting to MSBuild.' %
+ (msvs_value, msvs_tool_name, msvs_setting))
+ else:
+ # We don't know this setting. Give a warning.
+ print >> stderr, ('Warning: unrecognized setting %s/%s '
+ 'while converting to MSBuild.' % (msvs_tool_name, msvs_setting))
+ else:
+ print >> stderr, ('Warning: unrecognized tool %s while converting to '
+ 'MSBuild.' % msvs_tool_name)
+ return msbuild_settings
+
+
+def ValidateMSVSSettings(settings, stderr=sys.stderr):
+ """ Validates that the names of the settings are valid for MSVS.
+
+ Args:
+ settings: A dictionary. The key is the tool name. The values are
+ themselves dictionaries of settings and their values.
+ stderr: The stream receiving the error messages.
+ """
+ _ValidateSettings(_msvs_validators, settings, stderr)
+
+
+def ValidateMSBuildSettings(settings, stderr=sys.stderr):
+ """ Validates that the names of the settings are valid for MSBuild.
+
+ Args:
+ settings: A dictionary. The key is the tool name. The values are
+ themselves dictionaries of settings and their values.
+ stderr: The stream receiving the error messages.
+ """
+ _ValidateSettings(_msbuild_validators, settings, stderr)
+
+
+def _ValidateSettings(validators, settings, stderr):
+ """ Validates that the settings are valid for MSBuild or MSVS.
+
+ We currently only validate the names of the settings, not their values.
+
+ Args:
+ validators: A dictionary of tools and their validators.
+ settings: A dictionary. The key is the tool name. The values are
+ themselves dictionaries of settings and their values.
+ stderr: The stream receiving the error messages.
+ """
+ for tool_name in settings:
+ if tool_name in validators:
+ tool_validators = validators[tool_name]
+ for setting, value in settings[tool_name].iteritems():
+ if setting in tool_validators:
+ try:
+ tool_validators[setting](value)
+ except ValueError:
+ print >> stderr, ('Warning: unrecognized value "%s" for %s/%s' %
+ (value, tool_name, setting))
+ #except TypeError: #(jeanluc)
+ # print ('***value "%s" for %s/%s' % (value, tool_name, setting))
+ else:
+ print >> stderr, ('Warning: unrecognized setting %s/%s' %
+ (tool_name, setting))
+ else:
+ print >> stderr, ('Warning: unrecognized tool %s' % tool_name)
+
+
+# MSVS and MBuild names of the tools.
+_compile = {'msvs': 'VCCLCompilerTool', 'msbuild': 'ClCompile'}
+_link = {'msvs': 'VCLinkerTool', 'msbuild': 'Link'}
+_midl = {'msvs': 'VCMIDLTool', 'msbuild': 'Midl'}
+_rc = {'msvs': 'VCResourceCompilerTool', 'msbuild': 'ResourceCompile'}
+_lib = {'msvs': 'VCLibrarianTool', 'msbuild': 'Lib'}
+_manifest = {'msvs': 'VCManifestTool', 'msbuild': 'Mt'}
+
+
+_AddTool(_compile)
+_AddTool(_link)
+_AddTool(_midl)
+_AddTool(_rc)
+_AddTool(_lib)
+_AddTool(_manifest)
+# Add sections only found in the MSBuild settings.
+_msbuild_validators[''] = {}
+_msbuild_validators['ProjectReference'] = {}
+_msbuild_validators['ManifestResourceCompile'] = {}
+
+# Descriptions of the compiler options, i.e. VCCLCompilerTool in MSVS and
+# ClCompile in MSBuild.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\cl.xml" for
+# the schema of the MSBuild ClCompile settings.
+
+# Options that have the same name in MSVS and MSBuild
+_Same(_compile, 'AdditionalIncludeDirectories', _folder_list) # /I
+_Same(_compile, 'AdditionalOptions', _string_list)
+_Same(_compile, 'AdditionalUsingDirectories', _folder_list) # /AI
+_Same(_compile, 'AssemblerListingLocation', _file_name) # /Fa
+_Same(_compile, 'BrowseInformationFile', _file_name)
+_Same(_compile, 'BufferSecurityCheck', _boolean) # /GS
+_Same(_compile, 'DisableLanguageExtensions', _boolean) # /Za
+_Same(_compile, 'DisableSpecificWarnings', _string_list) # /wd
+_Same(_compile, 'EnableFiberSafeOptimizations', _boolean) # /GT
+_Same(_compile, 'EnablePREfast', _boolean) # /analyze Visible='false'
+_Same(_compile, 'ExpandAttributedSource', _boolean) # /Fx
+_Same(_compile, 'FloatingPointExceptions', _boolean) # /fp:except
+_Same(_compile, 'ForceConformanceInForLoopScope', _boolean) # /Zc:forScope
+_Same(_compile, 'ForcedIncludeFiles', _file_list) # /FI
+_Same(_compile, 'ForcedUsingFiles', _file_list) # /FU
+_Same(_compile, 'GenerateXMLDocumentationFiles', _boolean) # /doc
+_Same(_compile, 'IgnoreStandardIncludePath', _boolean) # /X
+_Same(_compile, 'MinimalRebuild', _boolean) # /Gm
+_Same(_compile, 'OmitDefaultLibName', _boolean) # /Zl
+_Same(_compile, 'OmitFramePointers', _boolean) # /Oy
+_Same(_compile, 'PreprocessorDefinitions', _string_list) # /D
+_Same(_compile, 'ProgramDataBaseFileName', _file_name) # /Fd
+_Same(_compile, 'RuntimeTypeInfo', _boolean) # /GR
+_Same(_compile, 'ShowIncludes', _boolean) # /showIncludes
+_Same(_compile, 'SmallerTypeCheck', _boolean) # /RTCc
+_Same(_compile, 'StringPooling', _boolean) # /GF
+_Same(_compile, 'SuppressStartupBanner', _boolean) # /nologo
+_Same(_compile, 'TreatWChar_tAsBuiltInType', _boolean) # /Zc:wchar_t
+_Same(_compile, 'UndefineAllPreprocessorDefinitions', _boolean) # /u
+_Same(_compile, 'UndefinePreprocessorDefinitions', _string_list) # /U
+_Same(_compile, 'UseFullPaths', _boolean) # /FC
+_Same(_compile, 'WholeProgramOptimization', _boolean) # /GL
+_Same(_compile, 'XMLDocumentationFileName', _file_name)
+
+_Same(_compile, 'AssemblerOutput',
+ _Enumeration(['NoListing',
+ 'AssemblyCode', # /FA
+ 'All', # /FAcs
+ 'AssemblyAndMachineCode', # /FAc
+ 'AssemblyAndSourceCode'])) # /FAs
+_Same(_compile, 'BasicRuntimeChecks',
+ _Enumeration(['Default',
+ 'StackFrameRuntimeCheck', # /RTCs
+ 'UninitializedLocalUsageCheck', # /RTCu
+ 'EnableFastChecks'])) # /RTC1
+_Same(_compile, 'BrowseInformation',
+ _Enumeration(['false',
+ 'true', # /FR
+ 'true'])) # /Fr
+_Same(_compile, 'CallingConvention',
+ _Enumeration(['Cdecl', # /Gd
+ 'FastCall', # /Gr
+ 'StdCall'])) # /Gz
+_Same(_compile, 'CompileAs',
+ _Enumeration(['Default',
+ 'CompileAsC', # /TC
+ 'CompileAsCpp'])) # /TP
+_Same(_compile, 'DebugInformationFormat',
+ _Enumeration(['', # Disabled
+ 'OldStyle', # /Z7
+ None,
+ 'ProgramDatabase', # /Zi
+ 'EditAndContinue'])) # /ZI
+_Same(_compile, 'EnableEnhancedInstructionSet',
+ _Enumeration(['NotSet',
+ 'StreamingSIMDExtensions', # /arch:SSE
+ 'StreamingSIMDExtensions2'])) # /arch:SSE2
+_Same(_compile, 'ErrorReporting',
+ _Enumeration(['None', # /errorReport:none
+ 'Prompt', # /errorReport:prompt
+ 'Queue'], # /errorReport:queue
+ new=['Send'])) # /errorReport:send"
+_Same(_compile, 'ExceptionHandling',
+ _Enumeration(['false',
+ 'Sync', # /EHsc
+ 'Async'], # /EHa
+ new=['SyncCThrow'])) # /EHs
+_Same(_compile, 'FavorSizeOrSpeed',
+ _Enumeration(['Neither',
+ 'Speed', # /Ot
+ 'Size'])) # /Os
+_Same(_compile, 'FloatingPointModel',
+ _Enumeration(['Precise', # /fp:precise
+ 'Strict', # /fp:strict
+ 'Fast'])) # /fp:fast
+_Same(_compile, 'InlineFunctionExpansion',
+ _Enumeration(['Default',
+ 'OnlyExplicitInline', # /Ob1
+ 'AnySuitable'], # /Ob2
+ new=['Disabled'])) # /Ob0
+_Same(_compile, 'Optimization',
+ _Enumeration(['Disabled', # /Od
+ 'MinSpace', # /O1
+ 'MaxSpeed', # /O2
+ 'Full'])) # /Ox
+_Same(_compile, 'RuntimeLibrary',
+ _Enumeration(['MultiThreaded', # /MT
+ 'MultiThreadedDebug', # /MTd
+ 'MultiThreadedDLL', # /MD
+ 'MultiThreadedDebugDLL'])) # /MDd
+_Same(_compile, 'StructMemberAlignment',
+ _Enumeration(['Default',
+ '1Byte', # /Zp1
+ '2Bytes', # /Zp2
+ '4Bytes', # /Zp4
+ '8Bytes', # /Zp8
+ '16Bytes'])) # /Zp16
+_Same(_compile, 'WarningLevel',
+ _Enumeration(['TurnOffAllWarnings', # /W0
+ 'Level1', # /W1
+ 'Level2', # /W2
+ 'Level3', # /W3
+ 'Level4'], # /W4
+ new=['EnableAllWarnings'])) # /Wall
+
+# Options found in MSVS that have been renamed in MSBuild.
+_Renamed(_compile, 'EnableFunctionLevelLinking', 'FunctionLevelLinking',
+ _boolean) # /Gy
+_Renamed(_compile, 'EnableIntrinsicFunctions', 'IntrinsicFunctions',
+ _boolean) # /Oi
+_Renamed(_compile, 'KeepComments', 'PreprocessKeepComments', _boolean) # /C
+_Renamed(_compile, 'ObjectFile', 'ObjectFileName', _file_name) # /Fo
+_Renamed(_compile, 'OpenMP', 'OpenMPSupport', _boolean) # /openmp
+_Renamed(_compile, 'PrecompiledHeaderThrough', 'PrecompiledHeaderFile',
+ _file_name) # Used with /Yc and /Yu
+_Renamed(_compile, 'PrecompiledHeaderFile', 'PrecompiledHeaderOutputFile',
+ _file_name) # /Fp
+_Renamed(_compile, 'UsePrecompiledHeader', 'PrecompiledHeader',
+ _Enumeration(['NotUsing', # VS recognized '' for this value too.
+ 'Create', # /Yc
+ 'Use'])) # /Yu
+_Renamed(_compile, 'WarnAsError', 'TreatWarningAsError', _boolean) # /WX
+
+_ConvertedToAdditionalOption(_compile, 'DefaultCharIsUnsigned', '/J')
+
+# MSVS options not found in MSBuild.
+_MSVSOnly(_compile, 'Detect64BitPortabilityProblems', _boolean)
+_MSVSOnly(_compile, 'UseUnicodeResponseFiles', _boolean)
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_compile, 'BuildingInIDE', _boolean)
+_MSBuildOnly(_compile, 'CompileAsManaged',
+ _Enumeration([], new=['false',
+ 'true', # /clr
+ 'Pure', # /clr:pure
+ 'Safe', # /clr:safe
+ 'OldSyntax'])) # /clr:oldSyntax
+_MSBuildOnly(_compile, 'CreateHotpatchableImage', _boolean) # /hotpatch
+_MSBuildOnly(_compile, 'MultiProcessorCompilation', _boolean) # /MP
+_MSBuildOnly(_compile, 'PreprocessOutputPath', _string) # /Fi
+_MSBuildOnly(_compile, 'ProcessorNumber', _integer) # the number of processors
+_MSBuildOnly(_compile, 'TrackerLogDirectory', _folder_name)
+_MSBuildOnly(_compile, 'TreatSpecificWarningsAsErrors', _string_list) # /we
+_MSBuildOnly(_compile, 'UseUnicodeForAssemblerListing', _boolean) # /FAu
+
+# Defines a setting that needs very customized processing
+_CustomGeneratePreprocessedFile(_compile, 'GeneratePreprocessedFile')
+
+
+# Directives for converting MSVS VCLinkerTool to MSBuild Link.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\link.xml" for
+# the schema of the MSBuild Link settings.
+
+# Options that have the same name in MSVS and MSBuild
+_Same(_link, 'AdditionalDependencies', _file_list)
+_Same(_link, 'AdditionalLibraryDirectories', _folder_list) # /LIBPATH
+_Same(_link, 'AdditionalManifestDependencies', _file_list) # /MANIFESTDEPENDENCY
+_Same(_link, 'AdditionalOptions', _string_list)
+_Same(_link, 'AddModuleNamesToAssembly', _file_list) # /ASSEMBLYMODULE
+_Same(_link, 'AllowIsolation', _boolean) # /ALLOWISOLATION
+_Same(_link, 'AssemblyLinkResource', _file_list) # /ASSEMBLYLINKRESOURCE
+_Same(_link, 'BaseAddress', _string) # /BASE
+_Same(_link, 'CLRUnmanagedCodeCheck', _boolean) # /CLRUNMANAGEDCODECHECK
+_Same(_link, 'DelayLoadDLLs', _file_list) # /DELAYLOAD
+_Same(_link, 'DelaySign', _boolean) # /DELAYSIGN
+_Same(_link, 'EmbedManagedResourceFile', _file_list) # /ASSEMBLYRESOURCE
+_Same(_link, 'EnableUAC', _boolean) # /MANIFESTUAC
+_Same(_link, 'EntryPointSymbol', _string) # /ENTRY
+_Same(_link, 'ForceSymbolReferences', _file_list) # /INCLUDE
+_Same(_link, 'FunctionOrder', _file_name) # /ORDER
+_Same(_link, 'GenerateDebugInformation', _boolean) # /DEBUG
+_Same(_link, 'GenerateMapFile', _boolean) # /MAP
+_Same(_link, 'HeapCommitSize', _string)
+_Same(_link, 'HeapReserveSize', _string) # /HEAP
+_Same(_link, 'IgnoreAllDefaultLibraries', _boolean) # /NODEFAULTLIB
+_Same(_link, 'IgnoreEmbeddedIDL', _boolean) # /IGNOREIDL
+_Same(_link, 'ImportLibrary', _file_name) # /IMPLIB
+_Same(_link, 'KeyContainer', _file_name) # /KEYCONTAINER
+_Same(_link, 'KeyFile', _file_name) # /KEYFILE
+_Same(_link, 'ManifestFile', _file_name) # /ManifestFile
+_Same(_link, 'MapExports', _boolean) # /MAPINFO:EXPORTS
+_Same(_link, 'MapFileName', _file_name)
+_Same(_link, 'MergedIDLBaseFileName', _file_name) # /IDLOUT
+_Same(_link, 'MergeSections', _string) # /MERGE
+_Same(_link, 'MidlCommandFile', _file_name) # /MIDL
+_Same(_link, 'ModuleDefinitionFile', _file_name) # /DEF
+_Same(_link, 'OutputFile', _file_name) # /OUT
+_Same(_link, 'PerUserRedirection', _boolean)
+_Same(_link, 'Profile', _boolean) # /PROFILE
+_Same(_link, 'ProfileGuidedDatabase', _file_name) # /PGD
+_Same(_link, 'ProgramDatabaseFile', _file_name) # /PDB
+_Same(_link, 'RegisterOutput', _boolean)
+_Same(_link, 'SetChecksum', _boolean) # /RELEASE
+_Same(_link, 'StackCommitSize', _string)
+_Same(_link, 'StackReserveSize', _string) # /STACK
+_Same(_link, 'StripPrivateSymbols', _file_name) # /PDBSTRIPPED
+_Same(_link, 'SupportUnloadOfDelayLoadedDLL', _boolean) # /DELAY:UNLOAD
+_Same(_link, 'SuppressStartupBanner', _boolean) # /NOLOGO
+_Same(_link, 'SwapRunFromCD', _boolean) # /SWAPRUN:CD
+_Same(_link, 'TurnOffAssemblyGeneration', _boolean) # /NOASSEMBLY
+_Same(_link, 'TypeLibraryFile', _file_name) # /TLBOUT
+_Same(_link, 'TypeLibraryResourceID', _integer) # /TLBID
+_Same(_link, 'UACUIAccess', _boolean) # /uiAccess='true'
+_Same(_link, 'Version', _string) # /VERSION
+
+_Same(_link, 'EnableCOMDATFolding', _newly_boolean) # /OPT:ICF
+_Same(_link, 'FixedBaseAddress', _newly_boolean) # /FIXED
+_Same(_link, 'LargeAddressAware', _newly_boolean) # /LARGEADDRESSAWARE
+_Same(_link, 'OptimizeReferences', _newly_boolean) # /OPT:REF
+_Same(_link, 'RandomizedBaseAddress', _newly_boolean) # /DYNAMICBASE
+_Same(_link, 'TerminalServerAware', _newly_boolean) # /TSAWARE
+
+_subsystem_enumeration = _Enumeration([
+ 'NotSet',
+ 'Console', # /SUBSYSTEM:CONSOLE
+ 'Windows', # /SUBSYSTEM:WINDOWS
+ 'Native', # /SUBSYSTEM:NATIVE
+ 'EFI Application', # /SUBSYSTEM:EFI_APPLICATION
+ 'EFI Boot Service Driver', # /SUBSYSTEM:EFI_BOOT_SERVICE_DRIVER
+ 'EFI ROM', # /SUBSYSTEM:EFI_ROM
+ 'EFI Runtime', # /SUBSYSTEM:EFI_RUNTIME_DRIVER
+ 'WindowsCE'], # /SUBSYSTEM:WINDOWSCE
+ new=['POSIX']) # /SUBSYSTEM:POSIX
+
+_target_machine_enumeration = _Enumeration([
+ 'NotSet',
+ 'MachineX86', # /MACHINE:X86
+ None,
+ 'MachineARM', # /MACHINE:ARM
+ 'MachineEBC', # /MACHINE:EBC
+ 'MachineIA64', # /MACHINE:IA64
+ None,
+ 'MachineMIPS', # /MACHINE:MIPS
+ 'MachineMIPS16', # /MACHINE:MIPS16
+ 'MachineMIPSFPU', # /MACHINE:MIPSFPU
+ 'MachineMIPSFPU16', # /MACHINE:MIPSFPU16
+ None,
+ None,
+ None,
+ 'MachineSH4', # /MACHINE:SH4
+ None,
+ 'MachineTHUMB', # /MACHINE:THUMB
+ 'MachineX64']) # /MACHINE:X64
+
+_Same(_link, 'AssemblyDebug',
+ _Enumeration(['',
+ 'true', # /ASSEMBLYDEBUG
+ 'false'])) # /ASSEMBLYDEBUG:DISABLE
+_Same(_link, 'CLRImageType',
+ _Enumeration(['Default',
+ 'ForceIJWImage', # /CLRIMAGETYPE:IJW
+ 'ForcePureILImage', # /Switch="CLRIMAGETYPE:PURE
+ 'ForceSafeILImage'])) # /Switch="CLRIMAGETYPE:SAFE
+_Same(_link, 'CLRThreadAttribute',
+ _Enumeration(['DefaultThreadingAttribute', # /CLRTHREADATTRIBUTE:NONE
+ 'MTAThreadingAttribute', # /CLRTHREADATTRIBUTE:MTA
+ 'STAThreadingAttribute'])) # /CLRTHREADATTRIBUTE:STA
+_Same(_link, 'DataExecutionPrevention',
+ _Enumeration(['',
+ 'false', # /NXCOMPAT:NO
+ 'true'])) # /NXCOMPAT
+_Same(_link, 'Driver',
+ _Enumeration(['NotSet',
+ 'Driver', # /Driver
+ 'UpOnly', # /DRIVER:UPONLY
+ 'WDM'])) # /DRIVER:WDM
+_Same(_link, 'LinkTimeCodeGeneration',
+ _Enumeration(['Default',
+ 'UseLinkTimeCodeGeneration', # /LTCG
+ 'PGInstrument', # /LTCG:PGInstrument
+ 'PGOptimization', # /LTCG:PGOptimize
+ 'PGUpdate'])) # /LTCG:PGUpdate
+_Same(_link, 'ShowProgress',
+ _Enumeration(['NotSet',
+ 'LinkVerbose', # /VERBOSE
+ 'LinkVerboseLib'], # /VERBOSE:Lib
+ new=['LinkVerboseICF', # /VERBOSE:ICF
+ 'LinkVerboseREF', # /VERBOSE:REF
+ 'LinkVerboseSAFESEH', # /VERBOSE:SAFESEH
+ 'LinkVerboseCLR'])) # /VERBOSE:CLR
+_Same(_link, 'SubSystem', _subsystem_enumeration)
+_Same(_link, 'TargetMachine', _target_machine_enumeration)
+_Same(_link, 'UACExecutionLevel',
+ _Enumeration(['AsInvoker', # /level='asInvoker'
+ 'HighestAvailable', # /level='highestAvailable'
+ 'RequireAdministrator'])) # /level='requireAdministrator'
+
+
+# Options found in MSVS that have been renamed in MSBuild.
+_Renamed(_link, 'ErrorReporting', 'LinkErrorReporting',
+ _Enumeration(['NoErrorReport', # /ERRORREPORT:NONE
+ 'PromptImmediately', # /ERRORREPORT:PROMPT
+ 'QueueForNextLogin'], # /ERRORREPORT:QUEUE
+ new=['SendErrorReport'])) # /ERRORREPORT:SEND
+_Renamed(_link, 'IgnoreDefaultLibraryNames', 'IgnoreSpecificDefaultLibraries',
+ _file_list) # /NODEFAULTLIB
+_Renamed(_link, 'ResourceOnlyDLL', 'NoEntryPoint', _boolean) # /NOENTRY
+_Renamed(_link, 'SwapRunFromNet', 'SwapRunFromNET', _boolean) # /SWAPRUN:NET
+
+_Moved(_link, 'GenerateManifest', '', _boolean)
+_Moved(_link, 'IgnoreImportLibrary', '', _boolean)
+_Moved(_link, 'LinkIncremental', '', _newly_boolean)
+_Moved(_link, 'LinkLibraryDependencies', 'ProjectReference', _boolean)
+_Moved(_link, 'UseLibraryDependencyInputs', 'ProjectReference', _boolean)
+
+# MSVS options not found in MSBuild.
+_MSVSOnly(_link, 'OptimizeForWindows98', _newly_boolean)
+_MSVSOnly(_link, 'UseUnicodeResponseFiles', _boolean)
+# TODO(jeanluc) I don't think these are genuine settings but byproducts of Gyp.
+_MSVSOnly(_link, 'AdditionalLibraryDirectories_excluded', _folder_list)
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_link, 'BuildingInIDE', _boolean)
+_MSBuildOnly(_link, 'ImageHasSafeExceptionHandlers', _boolean) # /SAFESEH
+_MSBuildOnly(_link, 'LinkDLL', _boolean) # /DLL Visible='false'
+_MSBuildOnly(_link, 'LinkStatus', _boolean) # /LTCG:STATUS
+_MSBuildOnly(_link, 'PreventDllBinding', _boolean) # /ALLOWBIND
+_MSBuildOnly(_link, 'SupportNobindOfDelayLoadedDLL', _boolean) # /DELAY:NOBIND
+_MSBuildOnly(_link, 'TrackerLogDirectory', _folder_name)
+_MSBuildOnly(_link, 'TreatLinkerWarningAsErrors', _boolean) # /WX
+_MSBuildOnly(_link, 'MinimumRequiredVersion', _string)
+_MSBuildOnly(_link, 'MSDOSStubFileName', _file_name) # /STUB Visible='false'
+_MSBuildOnly(_link, 'SectionAlignment', _integer) # /ALIGN
+_MSBuildOnly(_link, 'SpecifySectionAttributes', _string) # /SECTION
+_MSBuildOnly(_link, 'ForceFileOutput',
+ _Enumeration([], new=['Enabled', # /FORCE
+ 'MultiplyDefinedSymbolOnly', #/FORCE:MULTIPLE
+ 'UndefinedSymbolOnly'])) # /FORCE:UNRESOLVED
+_MSBuildOnly(_link, 'CreateHotPatchableImage',
+ _Enumeration([], new=['Enabled', # /FUNCTIONPADMIN
+ 'X86Image', # /FUNCTIONPADMIN:5
+ 'X64Image', # /FUNCTIONPADMIN:6
+ 'ItaniumImage'])) # /FUNCTIONPADMIN:16
+_MSBuildOnly(_link, 'CLRSupportLastError',
+ _Enumeration([], new=['Enabled', # /CLRSupportLastError
+ 'Disabled', # /CLRSupportLastError:NO
+ # /CLRSupportLastError:SYSTEMDLL
+ 'SystemDlls']))
+
+
+# Directives for converting VCResourceCompilerTool to ResourceCompile.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\rc.xml" for
+# the schema of the MSBuild ResourceCompile settings.
+
+_Same(_rc, 'AdditionalOptions', _string_list)
+_Same(_rc, 'AdditionalIncludeDirectories', _folder_list) # /I
+_Same(_rc, 'Culture', _Integer(msbuild_base=16))
+_Same(_rc, 'IgnoreStandardIncludePath', _boolean) # /X
+_Same(_rc, 'PreprocessorDefinitions', _string_list) # /D
+_Same(_rc, 'ResourceOutputFileName', _string) # /fo
+_Same(_rc, 'ShowProgress', _boolean) # /v
+# There is no UI in VisualStudio 2008 to set the following properties.
+# However they are found in CL and other tools. Include them here for
+# completeness, as they are very likely to have the same usage pattern.
+_Same(_rc, 'SuppressStartupBanner', _boolean) # /nologo
+_Same(_rc, 'UndefinePreprocessorDefinitions', _string_list) # /u
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_rc, 'NullTerminateStrings', _boolean) # /n
+_MSBuildOnly(_rc, 'TrackerLogDirectory', _folder_name)
+
+
+# Directives for converting VCMIDLTool to Midl.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\midl.xml" for
+# the schema of the MSBuild Midl settings.
+
+_Same(_midl, 'AdditionalIncludeDirectories', _folder_list) # /I
+_Same(_midl, 'AdditionalOptions', _string_list)
+_Same(_midl, 'CPreprocessOptions', _string) # /cpp_opt
+_Same(_midl, 'ErrorCheckAllocations', _boolean) # /error allocation
+_Same(_midl, 'ErrorCheckBounds', _boolean) # /error bounds_check
+_Same(_midl, 'ErrorCheckEnumRange', _boolean) # /error enum
+_Same(_midl, 'ErrorCheckRefPointers', _boolean) # /error ref
+_Same(_midl, 'ErrorCheckStubData', _boolean) # /error stub_data
+_Same(_midl, 'GenerateStublessProxies', _boolean) # /Oicf
+_Same(_midl, 'GenerateTypeLibrary', _boolean)
+_Same(_midl, 'HeaderFileName', _file_name) # /h
+_Same(_midl, 'IgnoreStandardIncludePath', _boolean) # /no_def_idir
+_Same(_midl, 'InterfaceIdentifierFileName', _file_name) # /iid
+_Same(_midl, 'MkTypLibCompatible', _boolean) # /mktyplib203
+_Same(_midl, 'OutputDirectory', _string) # /out
+_Same(_midl, 'PreprocessorDefinitions', _string_list) # /D
+_Same(_midl, 'ProxyFileName', _file_name) # /proxy
+_Same(_midl, 'RedirectOutputAndErrors', _file_name) # /o
+_Same(_midl, 'SuppressStartupBanner', _boolean) # /nologo
+_Same(_midl, 'TypeLibraryName', _file_name) # /tlb
+_Same(_midl, 'UndefinePreprocessorDefinitions', _string_list) # /U
+_Same(_midl, 'WarnAsError', _boolean) # /WX
+
+_Same(_midl, 'DefaultCharType',
+ _Enumeration(['Unsigned', # /char unsigned
+ 'Signed', # /char signed
+ 'Ascii'])) # /char ascii7
+_Same(_midl, 'TargetEnvironment',
+ _Enumeration(['NotSet',
+ 'Win32', # /env win32
+ 'Itanium', # /env ia64
+ 'X64'])) # /env x64
+_Same(_midl, 'EnableErrorChecks',
+ _Enumeration(['EnableCustom',
+ 'None', # /error none
+ 'All'])) # /error all
+_Same(_midl, 'StructMemberAlignment',
+ _Enumeration(['NotSet',
+ '1', # Zp1
+ '2', # Zp2
+ '4', # Zp4
+ '8'])) # Zp8
+_Same(_midl, 'WarningLevel',
+ _Enumeration(['0', # /W0
+ '1', # /W1
+ '2', # /W2
+ '3', # /W3
+ '4'])) # /W4
+
+_Renamed(_midl, 'DLLDataFileName', 'DllDataFileName', _file_name) # /dlldata
+_Renamed(_midl, 'ValidateParameters', 'ValidateAllParameters',
+ _boolean) # /robust
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_midl, 'ApplicationConfigurationMode', _boolean) # /app_config
+_MSBuildOnly(_midl, 'ClientStubFile', _file_name) # /cstub
+_MSBuildOnly(_midl, 'GenerateClientFiles',
+ _Enumeration([], new=['Stub', # /client stub
+ 'None'])) # /client none
+_MSBuildOnly(_midl, 'GenerateServerFiles',
+ _Enumeration([], new=['Stub', # /client stub
+ 'None'])) # /client none
+_MSBuildOnly(_midl, 'LocaleID', _integer) # /lcid DECIMAL
+_MSBuildOnly(_midl, 'ServerStubFile', _file_name) # /sstub
+_MSBuildOnly(_midl, 'SuppressCompilerWarnings', _boolean) # /no_warn
+_MSBuildOnly(_midl, 'TrackerLogDirectory', _folder_name)
+_MSBuildOnly(_midl, 'TypeLibFormat',
+ _Enumeration([], new=['NewFormat', # /newtlb
+ 'OldFormat'])) # /oldtlb
+
+
+# Directives for converting VCLibrarianTool to Lib.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\lib.xml" for
+# the schema of the MSBuild Lib settings.
+
+_Same(_lib, 'AdditionalDependencies', _file_list)
+_Same(_lib, 'AdditionalLibraryDirectories', _folder_list) # /LIBPATH
+_Same(_lib, 'AdditionalOptions', _string_list)
+_Same(_lib, 'ExportNamedFunctions', _string_list) # /EXPORT
+_Same(_lib, 'ForceSymbolReferences', _string) # /INCLUDE
+_Same(_lib, 'IgnoreAllDefaultLibraries', _boolean) # /NODEFAULTLIB
+_Same(_lib, 'IgnoreSpecificDefaultLibraries', _file_list) # /NODEFAULTLIB
+_Same(_lib, 'ModuleDefinitionFile', _file_name) # /DEF
+_Same(_lib, 'OutputFile', _file_name) # /OUT
+_Same(_lib, 'SuppressStartupBanner', _boolean) # /NOLOGO
+_Same(_lib, 'UseUnicodeResponseFiles', _boolean)
+
+# TODO(jeanluc) _link defines the same value that gets moved to
+# ProjectReference. We may want to validate that they are consistent.
+_Moved(_lib, 'LinkLibraryDependencies', 'ProjectReference', _boolean)
+
+# TODO(jeanluc) I don't think these are genuine settings but byproducts of Gyp.
+_MSVSOnly(_lib, 'AdditionalLibraryDirectories_excluded', _folder_list)
+
+_MSBuildOnly(_lib, 'DisplayLibrary', _string) # /LIST Visible='false'
+_MSBuildOnly(_lib, 'ErrorReporting',
+ _Enumeration([], new=['PromptImmediately', # /ERRORREPORT:PROMPT
+ 'QueueForNextLogin', # /ERRORREPORT:QUEUE
+ 'SendErrorReport', # /ERRORREPORT:SEND
+ 'NoErrorReport'])) # /ERRORREPORT:NONE
+_MSBuildOnly(_lib, 'LinkTimeCodeGeneration', _boolean) # /LTCG
+_MSBuildOnly(_lib, 'MinimumRequiredVersion', _string)
+_MSBuildOnly(_lib, 'Name', _file_name) # /NAME
+_MSBuildOnly(_lib, 'RemoveObjects', _file_list) # /REMOVE
+_MSBuildOnly(_lib, 'SubSystem', _subsystem_enumeration)
+_MSBuildOnly(_lib, 'TargetMachine', _target_machine_enumeration)
+_MSBuildOnly(_lib, 'TrackerLogDirectory', _folder_name)
+_MSBuildOnly(_lib, 'TreatLibWarningAsErrors', _boolean) # /WX
+_MSBuildOnly(_lib, 'Verbose', _boolean)
+
+
+# Directives for converting VCManifestTool to Mt.
+# See "c:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\1033\mt.xml" for
+# the schema of the MSBuild Lib settings.
+
+# Options that have the same name in MSVS and MSBuild
+_Same(_manifest, 'AdditionalManifestFiles', _file_list) # /manifest
+_Same(_manifest, 'AdditionalOptions', _string_list)
+_Same(_manifest, 'AssemblyIdentity', _string) # /identity:
+_Same(_manifest, 'ComponentFileName', _file_name) # /dll
+_Same(_manifest, 'GenerateCatalogFiles', _boolean) # /makecdfs
+_Same(_manifest, 'InputResourceManifests', _string) # /inputresource
+_Same(_manifest, 'OutputManifestFile', _file_name) # /out
+_Same(_manifest, 'RegistrarScriptFile', _file_name) # /rgs
+_Same(_manifest, 'ReplacementsFile', _file_name) # /replacements
+_Same(_manifest, 'SuppressStartupBanner', _boolean) # /nologo
+_Same(_manifest, 'TypeLibraryFile', _file_name) # /tlb:
+_Same(_manifest, 'UpdateFileHashes', _boolean) # /hashupdate
+_Same(_manifest, 'UpdateFileHashesSearchPath', _file_name)
+_Same(_manifest, 'VerboseOutput', _boolean) # /verbose
+
+# Options that have moved location.
+_MovedAndRenamed(_manifest, 'ManifestResourceFile',
+ 'ManifestResourceCompile',
+ 'ResourceOutputFileName',
+ _file_name)
+_Moved(_manifest, 'EmbedManifest', '', _boolean)
+
+# MSVS options not found in MSBuild.
+_MSVSOnly(_manifest, 'DependencyInformationFile', _file_name)
+_MSVSOnly(_manifest, 'UseFAT32Workaround', _boolean)
+_MSVSOnly(_manifest, 'UseUnicodeResponseFiles', _boolean)
+
+# MSBuild options not found in MSVS.
+_MSBuildOnly(_manifest, 'EnableDPIAwareness', _boolean)
+_MSBuildOnly(_manifest, 'GenerateCategoryTags', _boolean) # /category
+_MSBuildOnly(_manifest, 'ManifestFromManagedAssembly',
+ _file_name) # /managedassemblyname
+_MSBuildOnly(_manifest, 'OutputResourceManifests', _string) # /outputresource
+_MSBuildOnly(_manifest, 'SuppressDependencyElement', _boolean) # /nodependency
+_MSBuildOnly(_manifest, 'TrackerLogDirectory', _folder_name)
+
diff --git a/Source/ThirdParty/gyp/pylib/gyp/MSVSSettings_test.py b/Source/ThirdParty/gyp/pylib/gyp/MSVSSettings_test.py
new file mode 100644
index 000000000..c9ca7fdab
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/MSVSSettings_test.py
@@ -0,0 +1,1478 @@
+#!/usr/bin/python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Unit tests for the MSVSSettings.py file. """
+
+import sys
+import unittest
+import MSVSSettings
+import StringIO
+
+
+class TestSequenceFunctions(unittest.TestCase):
+
+ def setUp(self):
+ self.stderr = StringIO.StringIO()
+
+ def _ExpectedWarnings(self, expected):
+ """ Compares recorded lines to expected warnings. """
+ self.stderr.seek(0)
+ actual = self.stderr.read().split('\n')
+ actual = [line for line in actual if line != '']
+ self.assertEqual(sorted(expected), sorted(actual))
+
+ def test_ValidateMSVSSettings_tool_names(self):
+ """ Tests that only MSVS tool names are allowed. """
+ MSVSSettings.ValidateMSVSSettings({
+ 'VCCLCompilerTool': {},
+ 'VCLinkerTool': {},
+ 'VCMIDLTool': {},
+ 'foo': {},
+ 'VCResourceCompilerTool': {},
+ 'VCLibrarianTool': {},
+ 'VCManifestTool': {},
+ 'ClCompile': {}},
+ self.stderr)
+ self._ExpectedWarnings([
+ 'Warning: unrecognized tool foo',
+ 'Warning: unrecognized tool ClCompile'])
+
+ def test_ValidateMSVSSettings_settings(self):
+ """ Tests that for invalid MSVS settings. """
+ MSVSSettings.ValidateMSVSSettings({
+ 'VCCLCompilerTool': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2',
+ 'AdditionalOptions': ['string1', 'string2'],
+ 'AdditionalUsingDirectories': 'folder1;folder2',
+ 'AssemblerListingLocation': 'a_file_name',
+ 'AssemblerOutput': '0',
+ 'BasicRuntimeChecks': '5',
+ 'BrowseInformation': 'fdkslj',
+ 'BrowseInformationFile': 'a_file_name',
+ 'BufferSecurityCheck': 'true',
+ 'CallingConvention': '-1',
+ 'CompileAs': '1',
+ 'DebugInformationFormat': '2',
+ 'DefaultCharIsUnsigned': 'true',
+ 'Detect64BitPortabilityProblems': 'true',
+ 'DisableLanguageExtensions': 'true',
+ 'DisableSpecificWarnings': 'string1;string2',
+ 'EnableEnhancedInstructionSet': '1',
+ 'EnableFiberSafeOptimizations': 'true',
+ 'EnableFunctionLevelLinking': 'true',
+ 'EnableIntrinsicFunctions': 'true',
+ 'EnablePREfast': 'true',
+ 'Enableprefast': 'bogus',
+ 'ErrorReporting': '1',
+ 'ExceptionHandling': '1',
+ 'ExpandAttributedSource': 'true',
+ 'FavorSizeOrSpeed': '1',
+ 'FloatingPointExceptions': 'true',
+ 'FloatingPointModel': '1',
+ 'ForceConformanceInForLoopScope': 'true',
+ 'ForcedIncludeFiles': 'file1;file2',
+ 'ForcedUsingFiles': 'file1;file2',
+ 'GeneratePreprocessedFile': '1',
+ 'GenerateXMLDocumentationFiles': 'true',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InlineFunctionExpansion': '1',
+ 'KeepComments': 'true',
+ 'MinimalRebuild': 'true',
+ 'ObjectFile': 'a_file_name',
+ 'OmitDefaultLibName': 'true',
+ 'OmitFramePointers': 'true',
+ 'OpenMP': 'true',
+ 'Optimization': '1',
+ 'PrecompiledHeaderFile': 'a_file_name',
+ 'PrecompiledHeaderThrough': 'a_file_name',
+ 'PreprocessorDefinitions': 'string1;string2',
+ 'ProgramDataBaseFileName': 'a_file_name',
+ 'RuntimeLibrary': '1',
+ 'RuntimeTypeInfo': 'true',
+ 'ShowIncludes': 'true',
+ 'SmallerTypeCheck': 'true',
+ 'StringPooling': 'true',
+ 'StructMemberAlignment': '1',
+ 'SuppressStartupBanner': 'true',
+ 'TreatWChar_tAsBuiltInType': 'true',
+ 'UndefineAllPreprocessorDefinitions': 'true',
+ 'UndefinePreprocessorDefinitions': 'string1;string2',
+ 'UseFullPaths': 'true',
+ 'UsePrecompiledHeader': '1',
+ 'UseUnicodeResponseFiles': 'true',
+ 'WarnAsError': 'true',
+ 'WarningLevel': '1',
+ 'WholeProgramOptimization': 'true',
+ 'XMLDocumentationFileName': 'a_file_name',
+ 'ZZXYZ': 'bogus'},
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': 'file1;file2',
+ 'AdditionalLibraryDirectories': 'folder1;folder2',
+ 'AdditionalManifestDependencies': 'file1;file2',
+ 'AdditionalOptions': 'a string1',
+ 'AddModuleNamesToAssembly': 'file1;file2',
+ 'AllowIsolation': 'true',
+ 'AssemblyDebug': '2',
+ 'AssemblyLinkResource': 'file1;file2',
+ 'BaseAddress': 'a string1',
+ 'CLRImageType': '2',
+ 'CLRThreadAttribute': '2',
+ 'CLRUnmanagedCodeCheck': 'true',
+ 'DataExecutionPrevention': '2',
+ 'DelayLoadDLLs': 'file1;file2',
+ 'DelaySign': 'true',
+ 'Driver': '2',
+ 'EmbedManagedResourceFile': 'file1;file2',
+ 'EnableCOMDATFolding': '2',
+ 'EnableUAC': 'true',
+ 'EntryPointSymbol': 'a string1',
+ 'ErrorReporting': '2',
+ 'FixedBaseAddress': '2',
+ 'ForceSymbolReferences': 'file1;file2',
+ 'FunctionOrder': 'a_file_name',
+ 'GenerateDebugInformation': 'true',
+ 'GenerateManifest': 'true',
+ 'GenerateMapFile': 'true',
+ 'HeapCommitSize': 'a string1',
+ 'HeapReserveSize': 'a string1',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreDefaultLibraryNames': 'file1;file2',
+ 'IgnoreEmbeddedIDL': 'true',
+ 'IgnoreImportLibrary': 'true',
+ 'ImportLibrary': 'a_file_name',
+ 'KeyContainer': 'a_file_name',
+ 'KeyFile': 'a_file_name',
+ 'LargeAddressAware': '2',
+ 'LinkIncremental': '2',
+ 'LinkLibraryDependencies': 'true',
+ 'LinkTimeCodeGeneration': '2',
+ 'ManifestFile': 'a_file_name',
+ 'MapExports': 'true',
+ 'MapFileName': 'a_file_name',
+ 'MergedIDLBaseFileName': 'a_file_name',
+ 'MergeSections': 'a string1',
+ 'MidlCommandFile': 'a_file_name',
+ 'ModuleDefinitionFile': 'a_file_name',
+ 'OptimizeForWindows98': '1',
+ 'OptimizeReferences': '2',
+ 'OutputFile': 'a_file_name',
+ 'PerUserRedirection': 'true',
+ 'Profile': 'true',
+ 'ProfileGuidedDatabase': 'a_file_name',
+ 'ProgramDatabaseFile': 'a_file_name',
+ 'RandomizedBaseAddress': '2',
+ 'RegisterOutput': 'true',
+ 'ResourceOnlyDLL': 'true',
+ 'SetChecksum': 'true',
+ 'ShowProgress': '2',
+ 'StackCommitSize': 'a string1',
+ 'StackReserveSize': 'a string1',
+ 'StripPrivateSymbols': 'a_file_name',
+ 'SubSystem': '2',
+ 'SupportUnloadOfDelayLoadedDLL': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'SwapRunFromCD': 'true',
+ 'SwapRunFromNet': 'true',
+ 'TargetMachine': '2',
+ 'TerminalServerAware': '2',
+ 'TurnOffAssemblyGeneration': 'true',
+ 'TypeLibraryFile': 'a_file_name',
+ 'TypeLibraryResourceID': '33',
+ 'UACExecutionLevel': '2',
+ 'UACUIAccess': 'true',
+ 'UseLibraryDependencyInputs': 'true',
+ 'UseUnicodeResponseFiles': 'true',
+ 'Version': 'a string1'},
+ 'VCMIDLTool': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2',
+ 'AdditionalOptions': 'a string1',
+ 'CPreprocessOptions': 'a string1',
+ 'DefaultCharType': '1',
+ 'DLLDataFileName': 'a_file_name',
+ 'EnableErrorChecks': '1',
+ 'ErrorCheckAllocations': 'true',
+ 'ErrorCheckBounds': 'true',
+ 'ErrorCheckEnumRange': 'true',
+ 'ErrorCheckRefPointers': 'true',
+ 'ErrorCheckStubData': 'true',
+ 'GenerateStublessProxies': 'true',
+ 'GenerateTypeLibrary': 'true',
+ 'HeaderFileName': 'a_file_name',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InterfaceIdentifierFileName': 'a_file_name',
+ 'MkTypLibCompatible': 'true',
+ 'notgood': 'bogus',
+ 'OutputDirectory': 'a string1',
+ 'PreprocessorDefinitions': 'string1;string2',
+ 'ProxyFileName': 'a_file_name',
+ 'RedirectOutputAndErrors': 'a_file_name',
+ 'StructMemberAlignment': '1',
+ 'SuppressStartupBanner': 'true',
+ 'TargetEnvironment': '1',
+ 'TypeLibraryName': 'a_file_name',
+ 'UndefinePreprocessorDefinitions': 'string1;string2',
+ 'ValidateParameters': 'true',
+ 'WarnAsError': 'true',
+ 'WarningLevel': '1'},
+ 'VCResourceCompilerTool': {
+ 'AdditionalOptions': 'a string1',
+ 'AdditionalIncludeDirectories': 'folder1;folder2',
+ 'Culture': '1003',
+ 'IgnoreStandardIncludePath': 'true',
+ 'notgood2': 'bogus',
+ 'PreprocessorDefinitions': 'string1;string2',
+ 'ResourceOutputFileName': 'a string1',
+ 'ShowProgress': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'UndefinePreprocessorDefinitions': 'string1;string2'},
+ 'VCLibrarianTool': {
+ 'AdditionalDependencies': 'file1;file2',
+ 'AdditionalLibraryDirectories': 'folder1;folder2',
+ 'AdditionalOptions': 'a string1',
+ 'ExportNamedFunctions': 'string1;string2',
+ 'ForceSymbolReferences': 'a string1',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreSpecificDefaultLibraries': 'file1;file2',
+ 'LinkLibraryDependencies': 'true',
+ 'ModuleDefinitionFile': 'a_file_name',
+ 'OutputFile': 'a_file_name',
+ 'SuppressStartupBanner': 'true',
+ 'UseUnicodeResponseFiles': 'true'},
+ 'VCManifestTool': {
+ 'AdditionalManifestFiles': 'file1;file2',
+ 'AdditionalOptions': 'a string1',
+ 'AssemblyIdentity': 'a string1',
+ 'ComponentFileName': 'a_file_name',
+ 'DependencyInformationFile': 'a_file_name',
+ 'GenerateCatalogFiles': 'true',
+ 'InputResourceManifests': 'a string1',
+ 'ManifestResourceFile': 'a_file_name',
+ 'OutputManifestFile': 'a_file_name',
+ 'RegistrarScriptFile': 'a_file_name',
+ 'ReplacementsFile': 'a_file_name',
+ 'SuppressStartupBanner': 'true',
+ 'TypeLibraryFile': 'a_file_name',
+ 'UpdateFileHashes': 'truel',
+ 'UpdateFileHashesSearchPath': 'a_file_name',
+ 'UseFAT32Workaround': 'true',
+ 'UseUnicodeResponseFiles': 'true',
+ 'VerboseOutput': 'true'}},
+ self.stderr)
+ self._ExpectedWarnings([
+ 'Warning: unrecognized value "5" for VCCLCompilerTool/'
+ 'BasicRuntimeChecks',
+ 'Warning: unrecognized value "fdkslj" for VCCLCompilerTool/'
+ 'BrowseInformation',
+ 'Warning: unrecognized value "-1" for VCCLCompilerTool/'
+ 'CallingConvention',
+ 'Warning: unrecognized value "2" for VCCLCompilerTool/'
+ 'DebugInformationFormat',
+ 'Warning: unrecognized setting VCCLCompilerTool/Enableprefast',
+ 'Warning: unrecognized setting VCCLCompilerTool/ZZXYZ',
+ 'Warning: unrecognized value "2" for VCLinkerTool/TargetMachine',
+ 'Warning: unrecognized setting VCMIDLTool/notgood',
+ 'Warning: unrecognized setting VCResourceCompilerTool/notgood2',
+ 'Warning: unrecognized value "truel" for VCManifestTool/'
+ 'UpdateFileHashes'])
+
+ def test_ValidateMSBuildSettings_settings(self):
+ """ Tests that for invalid MSBuild settings. """
+ MSVSSettings.ValidateMSBuildSettings({
+ 'ClCompile': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2',
+ 'AdditionalOptions': ['string1', 'string2'],
+ 'AdditionalUsingDirectories': 'folder1;folder2',
+ 'AssemblerListingLocation': 'a_file_name',
+ 'AssemblerOutput': 'NoListing',
+ 'BasicRuntimeChecks': 'StackFrameRuntimeCheck',
+ 'BrowseInformation': 'false',
+ 'BrowseInformationFile': 'a_file_name',
+ 'BufferSecurityCheck': 'true',
+ 'BuildingInIDE': 'true',
+ 'CallingConvention': 'Cdecl',
+ 'CompileAs': 'CompileAsC',
+ 'CompileAsManaged': 'Pure',
+ 'CreateHotpatchableImage': 'true',
+ 'DebugInformationFormat': 'ProgramDatabase',
+ 'DisableLanguageExtensions': 'true',
+ 'DisableSpecificWarnings': 'string1;string2',
+ 'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions',
+ 'EnableFiberSafeOptimizations': 'true',
+ 'EnablePREfast': 'true',
+ 'Enableprefast': 'bogus',
+ 'ErrorReporting': 'Prompt',
+ 'ExceptionHandling': 'SyncCThrow',
+ 'ExpandAttributedSource': 'true',
+ 'FavorSizeOrSpeed': 'Neither',
+ 'FloatingPointExceptions': 'true',
+ 'FloatingPointModel': 'Precise',
+ 'ForceConformanceInForLoopScope': 'true',
+ 'ForcedIncludeFiles': 'file1;file2',
+ 'ForcedUsingFiles': 'file1;file2',
+ 'FunctionLevelLinking': 'false',
+ 'GenerateXMLDocumentationFiles': 'true',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InlineFunctionExpansion': 'OnlyExplicitInline',
+ 'IntrinsicFunctions': 'false',
+ 'MinimalRebuild': 'true',
+ 'MultiProcessorCompilation': 'true',
+ 'ObjectFileName': 'a_file_name',
+ 'OmitDefaultLibName': 'true',
+ 'OmitFramePointers': 'true',
+ 'OpenMPSupport': 'true',
+ 'Optimization': 'Disabled',
+ 'PrecompiledHeader': 'NotUsing',
+ 'PrecompiledHeaderFile': 'a_file_name',
+ 'PrecompiledHeaderOutputFile': 'a_file_name',
+ 'PreprocessKeepComments': 'true',
+ 'PreprocessorDefinitions': 'string1;string2',
+ 'PreprocessOutputPath': 'a string1',
+ 'PreprocessSuppressLineNumbers': 'false',
+ 'PreprocessToFile': 'false',
+ 'ProcessorNumber': '33',
+ 'ProgramDataBaseFileName': 'a_file_name',
+ 'RuntimeLibrary': 'MultiThreaded',
+ 'RuntimeTypeInfo': 'true',
+ 'ShowIncludes': 'true',
+ 'SmallerTypeCheck': 'true',
+ 'StringPooling': 'true',
+ 'StructMemberAlignment': '1Byte',
+ 'SuppressStartupBanner': 'true',
+ 'TrackerLogDirectory': 'a_folder',
+ 'TreatSpecificWarningsAsErrors': 'string1;string2',
+ 'TreatWarningAsError': 'true',
+ 'TreatWChar_tAsBuiltInType': 'true',
+ 'UndefineAllPreprocessorDefinitions': 'true',
+ 'UndefinePreprocessorDefinitions': 'string1;string2',
+ 'UseFullPaths': 'true',
+ 'UseUnicodeForAssemblerListing': 'true',
+ 'WarningLevel': 'TurnOffAllWarnings',
+ 'WholeProgramOptimization': 'true',
+ 'XMLDocumentationFileName': 'a_file_name',
+ 'ZZXYZ': 'bogus'},
+ 'Link': {
+ 'AdditionalDependencies': 'file1;file2',
+ 'AdditionalLibraryDirectories': 'folder1;folder2',
+ 'AdditionalManifestDependencies': 'file1;file2',
+ 'AdditionalOptions': 'a string1',
+ 'AddModuleNamesToAssembly': 'file1;file2',
+ 'AllowIsolation': 'true',
+ 'AssemblyDebug': '',
+ 'AssemblyLinkResource': 'file1;file2',
+ 'BaseAddress': 'a string1',
+ 'BuildingInIDE': 'true',
+ 'CLRImageType': 'ForceIJWImage',
+ 'CLRSupportLastError': 'Enabled',
+ 'CLRThreadAttribute': 'MTAThreadingAttribute',
+ 'CLRUnmanagedCodeCheck': 'true',
+ 'CreateHotPatchableImage': 'X86Image',
+ 'DataExecutionPrevention': 'false',
+ 'DelayLoadDLLs': 'file1;file2',
+ 'DelaySign': 'true',
+ 'Driver': 'NotSet',
+ 'EmbedManagedResourceFile': 'file1;file2',
+ 'EnableCOMDATFolding': 'false',
+ 'EnableUAC': 'true',
+ 'EntryPointSymbol': 'a string1',
+ 'FixedBaseAddress': 'false',
+ 'ForceFileOutput': 'Enabled',
+ 'ForceSymbolReferences': 'file1;file2',
+ 'FunctionOrder': 'a_file_name',
+ 'GenerateDebugInformation': 'true',
+ 'GenerateMapFile': 'true',
+ 'HeapCommitSize': 'a string1',
+ 'HeapReserveSize': 'a string1',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreEmbeddedIDL': 'true',
+ 'IgnoreSpecificDefaultLibraries': 'a_file_list',
+ 'ImageHasSafeExceptionHandlers': 'true',
+ 'ImportLibrary': 'a_file_name',
+ 'KeyContainer': 'a_file_name',
+ 'KeyFile': 'a_file_name',
+ 'LargeAddressAware': 'false',
+ 'LinkDLL': 'true',
+ 'LinkErrorReporting': 'SendErrorReport',
+ 'LinkStatus': 'true',
+ 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration',
+ 'ManifestFile': 'a_file_name',
+ 'MapExports': 'true',
+ 'MapFileName': 'a_file_name',
+ 'MergedIDLBaseFileName': 'a_file_name',
+ 'MergeSections': 'a string1',
+ 'MidlCommandFile': 'a_file_name',
+ 'MinimumRequiredVersion': 'a string1',
+ 'ModuleDefinitionFile': 'a_file_name',
+ 'MSDOSStubFileName': 'a_file_name',
+ 'NoEntryPoint': 'true',
+ 'OptimizeReferences': 'false',
+ 'OutputFile': 'a_file_name',
+ 'PerUserRedirection': 'true',
+ 'PreventDllBinding': 'true',
+ 'Profile': 'true',
+ 'ProfileGuidedDatabase': 'a_file_name',
+ 'ProgramDatabaseFile': 'a_file_name',
+ 'RandomizedBaseAddress': 'false',
+ 'RegisterOutput': 'true',
+ 'SectionAlignment': '33',
+ 'SetChecksum': 'true',
+ 'ShowProgress': 'LinkVerboseREF',
+ 'SpecifySectionAttributes': 'a string1',
+ 'StackCommitSize': 'a string1',
+ 'StackReserveSize': 'a string1',
+ 'StripPrivateSymbols': 'a_file_name',
+ 'SubSystem': 'Console',
+ 'SupportNobindOfDelayLoadedDLL': 'true',
+ 'SupportUnloadOfDelayLoadedDLL': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'SwapRunFromCD': 'true',
+ 'SwapRunFromNET': 'true',
+ 'TargetMachine': 'MachineX86',
+ 'TerminalServerAware': 'false',
+ 'TrackerLogDirectory': 'a_folder',
+ 'TreatLinkerWarningAsErrors': 'true',
+ 'TurnOffAssemblyGeneration': 'true',
+ 'TypeLibraryFile': 'a_file_name',
+ 'TypeLibraryResourceID': '33',
+ 'UACExecutionLevel': 'AsInvoker',
+ 'UACUIAccess': 'true',
+ 'Version': 'a string1'},
+ 'ResourceCompile': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2',
+ 'AdditionalOptions': 'a string1',
+ 'Culture': '0x236',
+ 'IgnoreStandardIncludePath': 'true',
+ 'NullTerminateStrings': 'true',
+ 'PreprocessorDefinitions': 'string1;string2',
+ 'ResourceOutputFileName': 'a string1',
+ 'ShowProgress': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'TrackerLogDirectory': 'a_folder',
+ 'UndefinePreprocessorDefinitions': 'string1;string2'},
+ 'Midl': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2',
+ 'AdditionalOptions': 'a string1',
+ 'ApplicationConfigurationMode': 'true',
+ 'ClientStubFile': 'a_file_name',
+ 'CPreprocessOptions': 'a string1',
+ 'DefaultCharType': 'Signed',
+ 'DllDataFileName': 'a_file_name',
+ 'EnableErrorChecks': 'EnableCustom',
+ 'ErrorCheckAllocations': 'true',
+ 'ErrorCheckBounds': 'true',
+ 'ErrorCheckEnumRange': 'true',
+ 'ErrorCheckRefPointers': 'true',
+ 'ErrorCheckStubData': 'true',
+ 'GenerateClientFiles': 'Stub',
+ 'GenerateServerFiles': 'None',
+ 'GenerateStublessProxies': 'true',
+ 'GenerateTypeLibrary': 'true',
+ 'HeaderFileName': 'a_file_name',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InterfaceIdentifierFileName': 'a_file_name',
+ 'LocaleID': '33',
+ 'MkTypLibCompatible': 'true',
+ 'OutputDirectory': 'a string1',
+ 'PreprocessorDefinitions': 'string1;string2',
+ 'ProxyFileName': 'a_file_name',
+ 'RedirectOutputAndErrors': 'a_file_name',
+ 'ServerStubFile': 'a_file_name',
+ 'StructMemberAlignment': 'NotSet',
+ 'SuppressCompilerWarnings': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'TargetEnvironment': 'Itanium',
+ 'TrackerLogDirectory': 'a_folder',
+ 'TypeLibFormat': 'NewFormat',
+ 'TypeLibraryName': 'a_file_name',
+ 'UndefinePreprocessorDefinitions': 'string1;string2',
+ 'ValidateAllParameters': 'true',
+ 'WarnAsError': 'true',
+ 'WarningLevel': '1'},
+ 'Lib': {
+ 'AdditionalDependencies': 'file1;file2',
+ 'AdditionalLibraryDirectories': 'folder1;folder2',
+ 'AdditionalOptions': 'a string1',
+ 'DisplayLibrary': 'a string1',
+ 'ErrorReporting': 'PromptImmediately',
+ 'ExportNamedFunctions': 'string1;string2',
+ 'ForceSymbolReferences': 'a string1',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreSpecificDefaultLibraries': 'file1;file2',
+ 'LinkTimeCodeGeneration': 'true',
+ 'MinimumRequiredVersion': 'a string1',
+ 'ModuleDefinitionFile': 'a_file_name',
+ 'Name': 'a_file_name',
+ 'OutputFile': 'a_file_name',
+ 'RemoveObjects': 'file1;file2',
+ 'SubSystem': 'Console',
+ 'SuppressStartupBanner': 'true',
+ 'TargetMachine': 'MachineX86i',
+ 'TrackerLogDirectory': 'a_folder',
+ 'TreatLibWarningAsErrors': 'true',
+ 'UseUnicodeResponseFiles': 'true',
+ 'Verbose': 'true'},
+ 'Mt': {
+ 'AdditionalManifestFiles': 'file1;file2',
+ 'AdditionalOptions': 'a string1',
+ 'AssemblyIdentity': 'a string1',
+ 'ComponentFileName': 'a_file_name',
+ 'EnableDPIAwareness': 'fal',
+ 'GenerateCatalogFiles': 'truel',
+ 'GenerateCategoryTags': 'true',
+ 'InputResourceManifests': 'a string1',
+ 'ManifestFromManagedAssembly': 'a_file_name',
+ 'notgood3': 'bogus',
+ 'OutputManifestFile': 'a_file_name',
+ 'OutputResourceManifests': 'a string1',
+ 'RegistrarScriptFile': 'a_file_name',
+ 'ReplacementsFile': 'a_file_name',
+ 'SuppressDependencyElement': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'TrackerLogDirectory': 'a_folder',
+ 'TypeLibraryFile': 'a_file_name',
+ 'UpdateFileHashes': 'true',
+ 'UpdateFileHashesSearchPath': 'a_file_name',
+ 'VerboseOutput': 'true'},
+ 'ProjectReference': {
+ 'LinkLibraryDependencies': 'true',
+ 'UseLibraryDependencyInputs': 'true'},
+ 'ManifestResourceCompile': {
+ 'ResourceOutputFileName': 'a_file_name'},
+ '': {
+ 'EmbedManifest': 'true',
+ 'GenerateManifest': 'true',
+ 'IgnoreImportLibrary': 'true',
+ 'LinkIncremental': 'false'}},
+ self.stderr)
+ self._ExpectedWarnings([
+ 'Warning: unrecognized setting ClCompile/Enableprefast',
+ 'Warning: unrecognized setting ClCompile/ZZXYZ',
+ 'Warning: unrecognized setting Mt/notgood3',
+ 'Warning: unrecognized value "truel" for Mt/GenerateCatalogFiles',
+ 'Warning: unrecognized value "MachineX86i" for Lib/TargetMachine',
+ 'Warning: unrecognized value "fal" for Mt/EnableDPIAwareness'])
+
+ def test_ConvertToMsBuildSettings_empty(self):
+ """ Tests an empty conversion. """
+ msvs_settings = {}
+ expected_msbuild_settings = {}
+ actual_msbuild_settings = MSVSSettings.ConvertToMsBuildSettings(
+ msvs_settings,
+ self.stderr)
+ self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+ self._ExpectedWarnings([])
+
+ def test_ConvertToMsBuildSettings_minimal(self):
+ """ Tests a minimal conversion. """
+ msvs_settings = {
+ 'VCCLCompilerTool': {
+ 'AdditionalIncludeDirectories': 'dir1',
+ 'AdditionalOptions': '/foo',
+ 'BasicRuntimeChecks': '0',
+ },
+ 'VCLinkerTool': {
+ 'LinkTimeCodeGeneration': '1',
+ 'ErrorReporting': '1',
+ 'DataExecutionPrevention': '2',
+ },
+ }
+ expected_msbuild_settings = {
+ 'ClCompile': {
+ 'AdditionalIncludeDirectories': 'dir1',
+ 'AdditionalOptions': '/foo',
+ 'BasicRuntimeChecks': 'Default',
+ },
+ 'Link': {
+ 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration',
+ 'LinkErrorReporting': 'PromptImmediately',
+ 'DataExecutionPrevention': 'true',
+ },
+ }
+ actual_msbuild_settings = MSVSSettings.ConvertToMsBuildSettings(
+ msvs_settings,
+ self.stderr)
+ self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+ self._ExpectedWarnings([])
+
+ def test_ConvertToMsBuildSettings_warnings(self):
+ """ Tests conversion that generates warnings. """
+ msvs_settings = {
+ 'VCCLCompilerTool': {
+ 'AdditionalIncludeDirectories': '1',
+ 'AdditionalOptions': '2',
+ # These are incorrect values:
+ 'BasicRuntimeChecks': '12',
+ 'BrowseInformation': '21',
+ 'UsePrecompiledHeader': '13',
+ 'GeneratePreprocessedFile': '14'},
+ 'VCLinkerTool': {
+ # These are incorrect values:
+ 'Driver': '10',
+ 'LinkTimeCodeGeneration': '31',
+ 'ErrorReporting': '21',
+ 'FixedBaseAddress': '6'},
+ 'VCResourceCompilerTool': {
+ # Custom
+ 'Culture': '1003'}}
+ expected_msbuild_settings = {
+ 'ClCompile': {
+ 'AdditionalIncludeDirectories': '1',
+ 'AdditionalOptions': '2'},
+ 'Link': {},
+ 'ResourceCompile': {
+ # Custom
+ 'Culture': '0x03eb'}}
+ actual_msbuild_settings = MSVSSettings.ConvertToMsBuildSettings(
+ msvs_settings,
+ self.stderr)
+ self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+ self._ExpectedWarnings([
+ 'Warning: unrecognized value "12" for VCCLCompilerTool/'
+ 'BasicRuntimeChecks while converting to MSBuild.',
+ 'Warning: unrecognized value "21" for VCCLCompilerTool/'
+ 'BrowseInformation while converting to MSBuild.',
+ 'Warning: unrecognized value "13" for VCCLCompilerTool/'
+ 'UsePrecompiledHeader while converting to MSBuild.',
+ 'Warning: unrecognized value "14" for VCCLCompilerTool/'
+ 'GeneratePreprocessedFile while converting to MSBuild.',
+
+ 'Warning: unrecognized value "10" for VCLinkerTool/'
+ 'Driver while converting to MSBuild.',
+ 'Warning: unrecognized value "31" for VCLinkerTool/'
+ 'LinkTimeCodeGeneration while converting to MSBuild.',
+ 'Warning: unrecognized value "21" for VCLinkerTool/'
+ 'ErrorReporting while converting to MSBuild.',
+ 'Warning: unrecognized value "6" for VCLinkerTool/'
+ 'FixedBaseAddress while converting to MSBuild.',
+ ])
+
+ def test_ConvertToMsBuildSettings_full_synthetic(self):
+ """ Tests conversion of all the MsBuild settings. """
+ msvs_settings = {
+ 'VCCLCompilerTool': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+ 'AdditionalOptions': 'a_string',
+ 'AdditionalUsingDirectories': 'folder1;folder2;folder3',
+ 'AssemblerListingLocation': 'a_file_name',
+ 'AssemblerOutput': '0',
+ 'BasicRuntimeChecks': '1',
+ 'BrowseInformation': '2',
+ 'BrowseInformationFile': 'a_file_name',
+ 'BufferSecurityCheck': 'true',
+ 'CallingConvention': '0',
+ 'CompileAs': '1',
+ 'DebugInformationFormat': '4',
+ 'DefaultCharIsUnsigned': 'true',
+ 'Detect64BitPortabilityProblems': 'true',
+ 'DisableLanguageExtensions': 'true',
+ 'DisableSpecificWarnings': 'd1;d2;d3',
+ 'EnableEnhancedInstructionSet': '0',
+ 'EnableFiberSafeOptimizations': 'true',
+ 'EnableFunctionLevelLinking': 'true',
+ 'EnableIntrinsicFunctions': 'true',
+ 'EnablePREfast': 'true',
+ 'ErrorReporting': '1',
+ 'ExceptionHandling': '2',
+ 'ExpandAttributedSource': 'true',
+ 'FavorSizeOrSpeed': '0',
+ 'FloatingPointExceptions': 'true',
+ 'FloatingPointModel': '1',
+ 'ForceConformanceInForLoopScope': 'true',
+ 'ForcedIncludeFiles': 'file1;file2;file3',
+ 'ForcedUsingFiles': 'file1;file2;file3',
+ 'GeneratePreprocessedFile': '1',
+ 'GenerateXMLDocumentationFiles': 'true',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InlineFunctionExpansion': '2',
+ 'KeepComments': 'true',
+ 'MinimalRebuild': 'true',
+ 'ObjectFile': 'a_file_name',
+ 'OmitDefaultLibName': 'true',
+ 'OmitFramePointers': 'true',
+ 'OpenMP': 'true',
+ 'Optimization': '3',
+ 'PrecompiledHeaderFile': 'a_file_name',
+ 'PrecompiledHeaderThrough': 'a_file_name',
+ 'PreprocessorDefinitions': 'd1;d2;d3',
+ 'ProgramDataBaseFileName': 'a_file_name',
+ 'RuntimeLibrary': '0',
+ 'RuntimeTypeInfo': 'true',
+ 'ShowIncludes': 'true',
+ 'SmallerTypeCheck': 'true',
+ 'StringPooling': 'true',
+ 'StructMemberAlignment': '1',
+ 'SuppressStartupBanner': 'true',
+ 'TreatWChar_tAsBuiltInType': 'true',
+ 'UndefineAllPreprocessorDefinitions': 'true',
+ 'UndefinePreprocessorDefinitions': 'd1;d2;d3',
+ 'UseFullPaths': 'true',
+ 'UsePrecompiledHeader': '1',
+ 'UseUnicodeResponseFiles': 'true',
+ 'WarnAsError': 'true',
+ 'WarningLevel': '2',
+ 'WholeProgramOptimization': 'true',
+ 'XMLDocumentationFileName': 'a_file_name'},
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': 'file1;file2;file3',
+ 'AdditionalLibraryDirectories': 'folder1;folder2;folder3',
+ 'AdditionalLibraryDirectories_excluded': 'folder1;folder2;folder3',
+ 'AdditionalManifestDependencies': 'file1;file2;file3',
+ 'AdditionalOptions': 'a_string',
+ 'AddModuleNamesToAssembly': 'file1;file2;file3',
+ 'AllowIsolation': 'true',
+ 'AssemblyDebug': '0',
+ 'AssemblyLinkResource': 'file1;file2;file3',
+ 'BaseAddress': 'a_string',
+ 'CLRImageType': '1',
+ 'CLRThreadAttribute': '2',
+ 'CLRUnmanagedCodeCheck': 'true',
+ 'DataExecutionPrevention': '0',
+ 'DelayLoadDLLs': 'file1;file2;file3',
+ 'DelaySign': 'true',
+ 'Driver': '1',
+ 'EmbedManagedResourceFile': 'file1;file2;file3',
+ 'EnableCOMDATFolding': '0',
+ 'EnableUAC': 'true',
+ 'EntryPointSymbol': 'a_string',
+ 'ErrorReporting': '0',
+ 'FixedBaseAddress': '1',
+ 'ForceSymbolReferences': 'file1;file2;file3',
+ 'FunctionOrder': 'a_file_name',
+ 'GenerateDebugInformation': 'true',
+ 'GenerateManifest': 'true',
+ 'GenerateMapFile': 'true',
+ 'HeapCommitSize': 'a_string',
+ 'HeapReserveSize': 'a_string',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreDefaultLibraryNames': 'file1;file2;file3',
+ 'IgnoreEmbeddedIDL': 'true',
+ 'IgnoreImportLibrary': 'true',
+ 'ImportLibrary': 'a_file_name',
+ 'KeyContainer': 'a_file_name',
+ 'KeyFile': 'a_file_name',
+ 'LargeAddressAware': '2',
+ 'LinkIncremental': '1',
+ 'LinkLibraryDependencies': 'true',
+ 'LinkTimeCodeGeneration': '2',
+ 'ManifestFile': 'a_file_name',
+ 'MapExports': 'true',
+ 'MapFileName': 'a_file_name',
+ 'MergedIDLBaseFileName': 'a_file_name',
+ 'MergeSections': 'a_string',
+ 'MidlCommandFile': 'a_file_name',
+ 'ModuleDefinitionFile': 'a_file_name',
+ 'OptimizeForWindows98': '1',
+ 'OptimizeReferences': '0',
+ 'OutputFile': 'a_file_name',
+ 'PerUserRedirection': 'true',
+ 'Profile': 'true',
+ 'ProfileGuidedDatabase': 'a_file_name',
+ 'ProgramDatabaseFile': 'a_file_name',
+ 'RandomizedBaseAddress': '1',
+ 'RegisterOutput': 'true',
+ 'ResourceOnlyDLL': 'true',
+ 'SetChecksum': 'true',
+ 'ShowProgress': '0',
+ 'StackCommitSize': 'a_string',
+ 'StackReserveSize': 'a_string',
+ 'StripPrivateSymbols': 'a_file_name',
+ 'SubSystem': '2',
+ 'SupportUnloadOfDelayLoadedDLL': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'SwapRunFromCD': 'true',
+ 'SwapRunFromNet': 'true',
+ 'TargetMachine': '3',
+ 'TerminalServerAware': '2',
+ 'TurnOffAssemblyGeneration': 'true',
+ 'TypeLibraryFile': 'a_file_name',
+ 'TypeLibraryResourceID': '33',
+ 'UACExecutionLevel': '1',
+ 'UACUIAccess': 'true',
+ 'UseLibraryDependencyInputs': 'false',
+ 'UseUnicodeResponseFiles': 'true',
+ 'Version': 'a_string'},
+ 'VCResourceCompilerTool': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+ 'AdditionalOptions': 'a_string',
+ 'Culture': '1003',
+ 'IgnoreStandardIncludePath': 'true',
+ 'PreprocessorDefinitions': 'd1;d2;d3',
+ 'ResourceOutputFileName': 'a_string',
+ 'ShowProgress': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'UndefinePreprocessorDefinitions': 'd1;d2;d3'},
+ 'VCMIDLTool': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+ 'AdditionalOptions': 'a_string',
+ 'CPreprocessOptions': 'a_string',
+ 'DefaultCharType': '0',
+ 'DLLDataFileName': 'a_file_name',
+ 'EnableErrorChecks': '2',
+ 'ErrorCheckAllocations': 'true',
+ 'ErrorCheckBounds': 'true',
+ 'ErrorCheckEnumRange': 'true',
+ 'ErrorCheckRefPointers': 'true',
+ 'ErrorCheckStubData': 'true',
+ 'GenerateStublessProxies': 'true',
+ 'GenerateTypeLibrary': 'true',
+ 'HeaderFileName': 'a_file_name',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InterfaceIdentifierFileName': 'a_file_name',
+ 'MkTypLibCompatible': 'true',
+ 'OutputDirectory': 'a_string',
+ 'PreprocessorDefinitions': 'd1;d2;d3',
+ 'ProxyFileName': 'a_file_name',
+ 'RedirectOutputAndErrors': 'a_file_name',
+ 'StructMemberAlignment': '3',
+ 'SuppressStartupBanner': 'true',
+ 'TargetEnvironment': '1',
+ 'TypeLibraryName': 'a_file_name',
+ 'UndefinePreprocessorDefinitions': 'd1;d2;d3',
+ 'ValidateParameters': 'true',
+ 'WarnAsError': 'true',
+ 'WarningLevel': '4'},
+ 'VCLibrarianTool': {
+ 'AdditionalDependencies': 'file1;file2;file3',
+ 'AdditionalLibraryDirectories': 'folder1;folder2;folder3',
+ 'AdditionalLibraryDirectories_excluded': 'folder1;folder2;folder3',
+ 'AdditionalOptions': 'a_string',
+ 'ExportNamedFunctions': 'd1;d2;d3',
+ 'ForceSymbolReferences': 'a_string',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3',
+ 'LinkLibraryDependencies': 'true',
+ 'ModuleDefinitionFile': 'a_file_name',
+ 'OutputFile': 'a_file_name',
+ 'SuppressStartupBanner': 'true',
+ 'UseUnicodeResponseFiles': 'true'},
+ 'VCManifestTool': {
+ 'AdditionalManifestFiles': 'file1;file2;file3',
+ 'AdditionalOptions': 'a_string',
+ 'AssemblyIdentity': 'a_string',
+ 'ComponentFileName': 'a_file_name',
+ 'DependencyInformationFile': 'a_file_name',
+ 'EmbedManifest': 'true',
+ 'GenerateCatalogFiles': 'true',
+ 'InputResourceManifests': 'a_string',
+ 'ManifestResourceFile': 'my_name',
+ 'OutputManifestFile': 'a_file_name',
+ 'RegistrarScriptFile': 'a_file_name',
+ 'ReplacementsFile': 'a_file_name',
+ 'SuppressStartupBanner': 'true',
+ 'TypeLibraryFile': 'a_file_name',
+ 'UpdateFileHashes': 'true',
+ 'UpdateFileHashesSearchPath': 'a_file_name',
+ 'UseFAT32Workaround': 'true',
+ 'UseUnicodeResponseFiles': 'true',
+ 'VerboseOutput': 'true'}}
+ expected_msbuild_settings = {
+ 'ClCompile': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+ 'AdditionalOptions': 'a_string /J',
+ 'AdditionalUsingDirectories': 'folder1;folder2;folder3',
+ 'AssemblerListingLocation': 'a_file_name',
+ 'AssemblerOutput': 'NoListing',
+ 'BasicRuntimeChecks': 'StackFrameRuntimeCheck',
+ 'BrowseInformation': 'true',
+ 'BrowseInformationFile': 'a_file_name',
+ 'BufferSecurityCheck': 'true',
+ 'CallingConvention': 'Cdecl',
+ 'CompileAs': 'CompileAsC',
+ 'DebugInformationFormat': 'EditAndContinue',
+ 'DisableLanguageExtensions': 'true',
+ 'DisableSpecificWarnings': 'd1;d2;d3',
+ 'EnableEnhancedInstructionSet': 'NotSet',
+ 'EnableFiberSafeOptimizations': 'true',
+ 'EnablePREfast': 'true',
+ 'ErrorReporting': 'Prompt',
+ 'ExceptionHandling': 'Async',
+ 'ExpandAttributedSource': 'true',
+ 'FavorSizeOrSpeed': 'Neither',
+ 'FloatingPointExceptions': 'true',
+ 'FloatingPointModel': 'Strict',
+ 'ForceConformanceInForLoopScope': 'true',
+ 'ForcedIncludeFiles': 'file1;file2;file3',
+ 'ForcedUsingFiles': 'file1;file2;file3',
+ 'FunctionLevelLinking': 'true',
+ 'GenerateXMLDocumentationFiles': 'true',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InlineFunctionExpansion': 'AnySuitable',
+ 'IntrinsicFunctions': 'true',
+ 'MinimalRebuild': 'true',
+ 'ObjectFileName': 'a_file_name',
+ 'OmitDefaultLibName': 'true',
+ 'OmitFramePointers': 'true',
+ 'OpenMPSupport': 'true',
+ 'Optimization': 'Full',
+ 'PrecompiledHeader': 'Create',
+ 'PrecompiledHeaderFile': 'a_file_name',
+ 'PrecompiledHeaderOutputFile': 'a_file_name',
+ 'PreprocessKeepComments': 'true',
+ 'PreprocessorDefinitions': 'd1;d2;d3',
+ 'PreprocessSuppressLineNumbers': 'false',
+ 'PreprocessToFile': 'true',
+ 'ProgramDataBaseFileName': 'a_file_name',
+ 'RuntimeLibrary': 'MultiThreaded',
+ 'RuntimeTypeInfo': 'true',
+ 'ShowIncludes': 'true',
+ 'SmallerTypeCheck': 'true',
+ 'StringPooling': 'true',
+ 'StructMemberAlignment': '1Byte',
+ 'SuppressStartupBanner': 'true',
+ 'TreatWarningAsError': 'true',
+ 'TreatWChar_tAsBuiltInType': 'true',
+ 'UndefineAllPreprocessorDefinitions': 'true',
+ 'UndefinePreprocessorDefinitions': 'd1;d2;d3',
+ 'UseFullPaths': 'true',
+ 'WarningLevel': 'Level2',
+ 'WholeProgramOptimization': 'true',
+ 'XMLDocumentationFileName': 'a_file_name'},
+ 'Link': {
+ 'AdditionalDependencies': 'file1;file2;file3',
+ 'AdditionalLibraryDirectories': 'folder1;folder2;folder3',
+ 'AdditionalManifestDependencies': 'file1;file2;file3',
+ 'AdditionalOptions': 'a_string',
+ 'AddModuleNamesToAssembly': 'file1;file2;file3',
+ 'AllowIsolation': 'true',
+ 'AssemblyDebug': '',
+ 'AssemblyLinkResource': 'file1;file2;file3',
+ 'BaseAddress': 'a_string',
+ 'CLRImageType': 'ForceIJWImage',
+ 'CLRThreadAttribute': 'STAThreadingAttribute',
+ 'CLRUnmanagedCodeCheck': 'true',
+ 'DataExecutionPrevention': '',
+ 'DelayLoadDLLs': 'file1;file2;file3',
+ 'DelaySign': 'true',
+ 'Driver': 'Driver',
+ 'EmbedManagedResourceFile': 'file1;file2;file3',
+ 'EnableCOMDATFolding': '',
+ 'EnableUAC': 'true',
+ 'EntryPointSymbol': 'a_string',
+ 'FixedBaseAddress': 'false',
+ 'ForceSymbolReferences': 'file1;file2;file3',
+ 'FunctionOrder': 'a_file_name',
+ 'GenerateDebugInformation': 'true',
+ 'GenerateMapFile': 'true',
+ 'HeapCommitSize': 'a_string',
+ 'HeapReserveSize': 'a_string',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreEmbeddedIDL': 'true',
+ 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3',
+ 'ImportLibrary': 'a_file_name',
+ 'KeyContainer': 'a_file_name',
+ 'KeyFile': 'a_file_name',
+ 'LargeAddressAware': 'true',
+ 'LinkErrorReporting': 'NoErrorReport',
+ 'LinkTimeCodeGeneration': 'PGInstrument',
+ 'ManifestFile': 'a_file_name',
+ 'MapExports': 'true',
+ 'MapFileName': 'a_file_name',
+ 'MergedIDLBaseFileName': 'a_file_name',
+ 'MergeSections': 'a_string',
+ 'MidlCommandFile': 'a_file_name',
+ 'ModuleDefinitionFile': 'a_file_name',
+ 'NoEntryPoint': 'true',
+ 'OptimizeReferences': '',
+ 'OutputFile': 'a_file_name',
+ 'PerUserRedirection': 'true',
+ 'Profile': 'true',
+ 'ProfileGuidedDatabase': 'a_file_name',
+ 'ProgramDatabaseFile': 'a_file_name',
+ 'RandomizedBaseAddress': 'false',
+ 'RegisterOutput': 'true',
+ 'SetChecksum': 'true',
+ 'ShowProgress': 'NotSet',
+ 'StackCommitSize': 'a_string',
+ 'StackReserveSize': 'a_string',
+ 'StripPrivateSymbols': 'a_file_name',
+ 'SubSystem': 'Windows',
+ 'SupportUnloadOfDelayLoadedDLL': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'SwapRunFromCD': 'true',
+ 'SwapRunFromNET': 'true',
+ 'TargetMachine': 'MachineARM',
+ 'TerminalServerAware': 'true',
+ 'TurnOffAssemblyGeneration': 'true',
+ 'TypeLibraryFile': 'a_file_name',
+ 'TypeLibraryResourceID': '33',
+ 'UACExecutionLevel': 'HighestAvailable',
+ 'UACUIAccess': 'true',
+ 'Version': 'a_string'},
+ 'ResourceCompile': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+ 'AdditionalOptions': 'a_string',
+ 'Culture': '0x03eb',
+ 'IgnoreStandardIncludePath': 'true',
+ 'PreprocessorDefinitions': 'd1;d2;d3',
+ 'ResourceOutputFileName': 'a_string',
+ 'ShowProgress': 'true',
+ 'SuppressStartupBanner': 'true',
+ 'UndefinePreprocessorDefinitions': 'd1;d2;d3'},
+ 'Midl': {
+ 'AdditionalIncludeDirectories': 'folder1;folder2;folder3',
+ 'AdditionalOptions': 'a_string',
+ 'CPreprocessOptions': 'a_string',
+ 'DefaultCharType': 'Unsigned',
+ 'DllDataFileName': 'a_file_name',
+ 'EnableErrorChecks': 'All',
+ 'ErrorCheckAllocations': 'true',
+ 'ErrorCheckBounds': 'true',
+ 'ErrorCheckEnumRange': 'true',
+ 'ErrorCheckRefPointers': 'true',
+ 'ErrorCheckStubData': 'true',
+ 'GenerateStublessProxies': 'true',
+ 'GenerateTypeLibrary': 'true',
+ 'HeaderFileName': 'a_file_name',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InterfaceIdentifierFileName': 'a_file_name',
+ 'MkTypLibCompatible': 'true',
+ 'OutputDirectory': 'a_string',
+ 'PreprocessorDefinitions': 'd1;d2;d3',
+ 'ProxyFileName': 'a_file_name',
+ 'RedirectOutputAndErrors': 'a_file_name',
+ 'StructMemberAlignment': '4',
+ 'SuppressStartupBanner': 'true',
+ 'TargetEnvironment': 'Win32',
+ 'TypeLibraryName': 'a_file_name',
+ 'UndefinePreprocessorDefinitions': 'd1;d2;d3',
+ 'ValidateAllParameters': 'true',
+ 'WarnAsError': 'true',
+ 'WarningLevel': '4'},
+ 'Lib': {
+ 'AdditionalDependencies': 'file1;file2;file3',
+ 'AdditionalLibraryDirectories': 'folder1;folder2;folder3',
+ 'AdditionalOptions': 'a_string',
+ 'ExportNamedFunctions': 'd1;d2;d3',
+ 'ForceSymbolReferences': 'a_string',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreSpecificDefaultLibraries': 'file1;file2;file3',
+ 'ModuleDefinitionFile': 'a_file_name',
+ 'OutputFile': 'a_file_name',
+ 'SuppressStartupBanner': 'true',
+ 'UseUnicodeResponseFiles': 'true'},
+ 'Mt': {
+ 'AdditionalManifestFiles': 'file1;file2;file3',
+ 'AdditionalOptions': 'a_string',
+ 'AssemblyIdentity': 'a_string',
+ 'ComponentFileName': 'a_file_name',
+ 'GenerateCatalogFiles': 'true',
+ 'InputResourceManifests': 'a_string',
+ 'OutputManifestFile': 'a_file_name',
+ 'RegistrarScriptFile': 'a_file_name',
+ 'ReplacementsFile': 'a_file_name',
+ 'SuppressStartupBanner': 'true',
+ 'TypeLibraryFile': 'a_file_name',
+ 'UpdateFileHashes': 'true',
+ 'UpdateFileHashesSearchPath': 'a_file_name',
+ 'VerboseOutput': 'true'},
+ 'ManifestResourceCompile': {
+ 'ResourceOutputFileName': 'my_name'},
+ 'ProjectReference': {
+ 'LinkLibraryDependencies': 'true',
+ 'UseLibraryDependencyInputs': 'false'},
+ '': {
+ 'EmbedManifest': 'true',
+ 'GenerateManifest': 'true',
+ 'IgnoreImportLibrary': 'true',
+ 'LinkIncremental': 'false'}}
+ actual_msbuild_settings = MSVSSettings.ConvertToMsBuildSettings(
+ msvs_settings,
+ self.stderr)
+ self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+ self._ExpectedWarnings([])
+
+ def test_ConvertToMsBuildSettings_actual(self):
+ """ Tests the conversion of an actual project.
+
+ A VS2008 project with most of the options defined was created through the
+ VS2008 IDE. It was then converted to VS2010. The tool settings found in
+ the .vcproj and .vcxproj files were converted to the two dictionaries
+ msvs_settings and expected_msbuild_settings.
+
+ Note that for many settings, the VS2010 converter adds macros like
+ %(AdditionalIncludeDirectories) to make sure than inherited values are
+ included. Since the Gyp projects we generate do not use inheritance,
+ we removed these macros. They were:
+ ClCompile:
+ AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)'
+ AdditionalOptions: ' %(AdditionalOptions)'
+ AdditionalUsingDirectories: ';%(AdditionalUsingDirectories)'
+ DisableSpecificWarnings: ';%(DisableSpecificWarnings)',
+ ForcedIncludeFiles: ';%(ForcedIncludeFiles)',
+ ForcedUsingFiles: ';%(ForcedUsingFiles)',
+ PreprocessorDefinitions: ';%(PreprocessorDefinitions)',
+ UndefinePreprocessorDefinitions:
+ ';%(UndefinePreprocessorDefinitions)',
+ Link:
+ AdditionalDependencies: ';%(AdditionalDependencies)',
+ AdditionalLibraryDirectories: ';%(AdditionalLibraryDirectories)',
+ AdditionalManifestDependencies:
+ ';%(AdditionalManifestDependencies)',
+ AdditionalOptions: ' %(AdditionalOptions)',
+ AddModuleNamesToAssembly: ';%(AddModuleNamesToAssembly)',
+ AssemblyLinkResource: ';%(AssemblyLinkResource)',
+ DelayLoadDLLs: ';%(DelayLoadDLLs)',
+ EmbedManagedResourceFile: ';%(EmbedManagedResourceFile)',
+ ForceSymbolReferences: ';%(ForceSymbolReferences)',
+ IgnoreSpecificDefaultLibraries:
+ ';%(IgnoreSpecificDefaultLibraries)',
+ ResourceCompile:
+ AdditionalIncludeDirectories: ';%(AdditionalIncludeDirectories)',
+ AdditionalOptions: ' %(AdditionalOptions)',
+ PreprocessorDefinitions: ';%(PreprocessorDefinitions)',
+ Mt:
+ AdditionalManifestFiles: ';%(AdditionalManifestFiles)',
+ AdditionalOptions: ' %(AdditionalOptions)',
+ InputResourceManifests: ';%(InputResourceManifests)',
+ """
+ msvs_settings = {
+ 'VCCLCompilerTool': {
+ 'AdditionalIncludeDirectories': 'dir1',
+ 'AdditionalOptions': '/more',
+ 'AdditionalUsingDirectories': 'test',
+ 'AssemblerListingLocation': '$(IntDir)\\a',
+ 'AssemblerOutput': '1',
+ 'BasicRuntimeChecks': '3',
+ 'BrowseInformation': '1',
+ 'BrowseInformationFile': '$(IntDir)\\e',
+ 'BufferSecurityCheck': 'false',
+ 'CallingConvention': '1',
+ 'CompileAs': '1',
+ 'DebugInformationFormat': '4',
+ 'DefaultCharIsUnsigned': 'true',
+ 'Detect64BitPortabilityProblems': 'true',
+ 'DisableLanguageExtensions': 'true',
+ 'DisableSpecificWarnings': 'abc',
+ 'EnableEnhancedInstructionSet': '1',
+ 'EnableFiberSafeOptimizations': 'true',
+ 'EnableFunctionLevelLinking': 'true',
+ 'EnableIntrinsicFunctions': 'true',
+ 'EnablePREfast': 'true',
+ 'ErrorReporting': '2',
+ 'ExceptionHandling': '2',
+ 'ExpandAttributedSource': 'true',
+ 'FavorSizeOrSpeed': '2',
+ 'FloatingPointExceptions': 'true',
+ 'FloatingPointModel': '1',
+ 'ForceConformanceInForLoopScope': 'false',
+ 'ForcedIncludeFiles': 'def',
+ 'ForcedUsingFiles': 'ge',
+ 'GeneratePreprocessedFile': '2',
+ 'GenerateXMLDocumentationFiles': 'true',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InlineFunctionExpansion': '1',
+ 'KeepComments': 'true',
+ 'MinimalRebuild': 'true',
+ 'ObjectFile': '$(IntDir)\\b',
+ 'OmitDefaultLibName': 'true',
+ 'OmitFramePointers': 'true',
+ 'OpenMP': 'true',
+ 'Optimization': '3',
+ 'PrecompiledHeaderFile': '$(IntDir)\\$(TargetName).pche',
+ 'PrecompiledHeaderThrough': 'StdAfx.hd',
+ 'PreprocessorDefinitions': 'WIN32;_DEBUG;_CONSOLE',
+ 'ProgramDataBaseFileName': '$(IntDir)\\vc90b.pdb',
+ 'RuntimeLibrary': '3',
+ 'RuntimeTypeInfo': 'false',
+ 'ShowIncludes': 'true',
+ 'SmallerTypeCheck': 'true',
+ 'StringPooling': 'true',
+ 'StructMemberAlignment': '3',
+ 'SuppressStartupBanner': 'false',
+ 'TreatWChar_tAsBuiltInType': 'false',
+ 'UndefineAllPreprocessorDefinitions': 'true',
+ 'UndefinePreprocessorDefinitions': 'wer',
+ 'UseFullPaths': 'true',
+ 'UsePrecompiledHeader': '0',
+ 'UseUnicodeResponseFiles': 'false',
+ 'WarnAsError': 'true',
+ 'WarningLevel': '3',
+ 'WholeProgramOptimization': 'true',
+ 'XMLDocumentationFileName': '$(IntDir)\\c'},
+ 'VCLinkerTool': {
+ 'AdditionalDependencies': 'zx',
+ 'AdditionalLibraryDirectories': 'asd',
+ 'AdditionalManifestDependencies': 's2',
+ 'AdditionalOptions': '/mor2',
+ 'AddModuleNamesToAssembly': 'd1',
+ 'AllowIsolation': 'false',
+ 'AssemblyDebug': '1',
+ 'AssemblyLinkResource': 'd5',
+ 'BaseAddress': '23423',
+ 'CLRImageType': '3',
+ 'CLRThreadAttribute': '1',
+ 'CLRUnmanagedCodeCheck': 'true',
+ 'DataExecutionPrevention': '0',
+ 'DelayLoadDLLs': 'd4',
+ 'DelaySign': 'true',
+ 'Driver': '2',
+ 'EmbedManagedResourceFile': 'd2',
+ 'EnableCOMDATFolding': '1',
+ 'EnableUAC': 'false',
+ 'EntryPointSymbol': 'f5',
+ 'ErrorReporting': '2',
+ 'FixedBaseAddress': '1',
+ 'ForceSymbolReferences': 'd3',
+ 'FunctionOrder': 'fssdfsd',
+ 'GenerateDebugInformation': 'true',
+ 'GenerateManifest': 'false',
+ 'GenerateMapFile': 'true',
+ 'HeapCommitSize': '13',
+ 'HeapReserveSize': '12',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreDefaultLibraryNames': 'flob;flok',
+ 'IgnoreEmbeddedIDL': 'true',
+ 'IgnoreImportLibrary': 'true',
+ 'ImportLibrary': 'f4',
+ 'KeyContainer': 'f7',
+ 'KeyFile': 'f6',
+ 'LargeAddressAware': '2',
+ 'LinkIncremental': '0',
+ 'LinkLibraryDependencies': 'false',
+ 'LinkTimeCodeGeneration': '1',
+ 'ManifestFile':
+ '$(IntDir)\\$(TargetFileName).2intermediate.manifest',
+ 'MapExports': 'true',
+ 'MapFileName': 'd5',
+ 'MergedIDLBaseFileName': 'f2',
+ 'MergeSections': 'f5',
+ 'MidlCommandFile': 'f1',
+ 'ModuleDefinitionFile': 'sdsd',
+ 'OptimizeForWindows98': '2',
+ 'OptimizeReferences': '2',
+ 'OutputFile': '$(OutDir)\\$(ProjectName)2.exe',
+ 'PerUserRedirection': 'true',
+ 'Profile': 'true',
+ 'ProfileGuidedDatabase': '$(TargetDir)$(TargetName).pgdd',
+ 'ProgramDatabaseFile': 'Flob.pdb',
+ 'RandomizedBaseAddress': '1',
+ 'RegisterOutput': 'true',
+ 'ResourceOnlyDLL': 'true',
+ 'SetChecksum': 'false',
+ 'ShowProgress': '1',
+ 'StackCommitSize': '15',
+ 'StackReserveSize': '14',
+ 'StripPrivateSymbols': 'd3',
+ 'SubSystem': '1',
+ 'SupportUnloadOfDelayLoadedDLL': 'true',
+ 'SuppressStartupBanner': 'false',
+ 'SwapRunFromCD': 'true',
+ 'SwapRunFromNet': 'true',
+ 'TargetMachine': '1',
+ 'TerminalServerAware': '1',
+ 'TurnOffAssemblyGeneration': 'true',
+ 'TypeLibraryFile': 'f3',
+ 'TypeLibraryResourceID': '12',
+ 'UACExecutionLevel': '2',
+ 'UACUIAccess': 'true',
+ 'UseLibraryDependencyInputs': 'true',
+ 'UseUnicodeResponseFiles': 'false',
+ 'Version': '333'},
+ 'VCResourceCompilerTool': {
+ 'AdditionalIncludeDirectories': 'f3',
+ 'AdditionalOptions': '/more3',
+ 'Culture': '3084',
+ 'IgnoreStandardIncludePath': 'true',
+ 'PreprocessorDefinitions': '_UNICODE;UNICODE2',
+ 'ResourceOutputFileName': '$(IntDir)/$(InputName)3.res',
+ 'ShowProgress': 'true'},
+ 'VCManifestTool': {
+ 'AdditionalManifestFiles': 'sfsdfsd',
+ 'AdditionalOptions': 'afdsdafsd',
+ 'AssemblyIdentity': 'sddfdsadfsa',
+ 'ComponentFileName': 'fsdfds',
+ 'DependencyInformationFile': '$(IntDir)\\mt.depdfd',
+ 'EmbedManifest': 'false',
+ 'GenerateCatalogFiles': 'true',
+ 'InputResourceManifests': 'asfsfdafs',
+ 'ManifestResourceFile':
+ '$(IntDir)\\$(TargetFileName).embed.manifest.resfdsf',
+ 'OutputManifestFile': '$(TargetPath).manifestdfs',
+ 'RegistrarScriptFile': 'sdfsfd',
+ 'ReplacementsFile': 'sdffsd',
+ 'SuppressStartupBanner': 'false',
+ 'TypeLibraryFile': 'sfsd',
+ 'UpdateFileHashes': 'true',
+ 'UpdateFileHashesSearchPath': 'sfsd',
+ 'UseFAT32Workaround': 'true',
+ 'UseUnicodeResponseFiles': 'false',
+ 'VerboseOutput': 'true'}}
+ expected_msbuild_settings = {
+ 'ClCompile': {
+ 'AdditionalIncludeDirectories': 'dir1',
+ 'AdditionalOptions': '/more /J',
+ 'AdditionalUsingDirectories': 'test',
+ 'AssemblerListingLocation': '$(IntDir)a',
+ 'AssemblerOutput': 'AssemblyCode',
+ 'BasicRuntimeChecks': 'EnableFastChecks',
+ 'BrowseInformation': 'true',
+ 'BrowseInformationFile': '$(IntDir)e',
+ 'BufferSecurityCheck': 'false',
+ 'CallingConvention': 'FastCall',
+ 'CompileAs': 'CompileAsC',
+ 'DebugInformationFormat': 'EditAndContinue',
+ 'DisableLanguageExtensions': 'true',
+ 'DisableSpecificWarnings': 'abc',
+ 'EnableEnhancedInstructionSet': 'StreamingSIMDExtensions',
+ 'EnableFiberSafeOptimizations': 'true',
+ 'EnablePREfast': 'true',
+ 'ErrorReporting': 'Queue',
+ 'ExceptionHandling': 'Async',
+ 'ExpandAttributedSource': 'true',
+ 'FavorSizeOrSpeed': 'Size',
+ 'FloatingPointExceptions': 'true',
+ 'FloatingPointModel': 'Strict',
+ 'ForceConformanceInForLoopScope': 'false',
+ 'ForcedIncludeFiles': 'def',
+ 'ForcedUsingFiles': 'ge',
+ 'FunctionLevelLinking': 'true',
+ 'GenerateXMLDocumentationFiles': 'true',
+ 'IgnoreStandardIncludePath': 'true',
+ 'InlineFunctionExpansion': 'OnlyExplicitInline',
+ 'IntrinsicFunctions': 'true',
+ 'MinimalRebuild': 'true',
+ 'ObjectFileName': '$(IntDir)b',
+ 'OmitDefaultLibName': 'true',
+ 'OmitFramePointers': 'true',
+ 'OpenMPSupport': 'true',
+ 'Optimization': 'Full',
+ 'PrecompiledHeader': 'NotUsing', # Actual conversion gives ''
+ 'PrecompiledHeaderFile': 'StdAfx.hd',
+ 'PrecompiledHeaderOutputFile': '$(IntDir)$(TargetName).pche',
+ 'PreprocessKeepComments': 'true',
+ 'PreprocessorDefinitions': 'WIN32;_DEBUG;_CONSOLE',
+ 'PreprocessSuppressLineNumbers': 'true',
+ 'PreprocessToFile': 'true',
+ 'ProgramDataBaseFileName': '$(IntDir)vc90b.pdb',
+ 'RuntimeLibrary': 'MultiThreadedDebugDLL',
+ 'RuntimeTypeInfo': 'false',
+ 'ShowIncludes': 'true',
+ 'SmallerTypeCheck': 'true',
+ 'StringPooling': 'true',
+ 'StructMemberAlignment': '4Bytes',
+ 'SuppressStartupBanner': 'false',
+ 'TreatWarningAsError': 'true',
+ 'TreatWChar_tAsBuiltInType': 'false',
+ 'UndefineAllPreprocessorDefinitions': 'true',
+ 'UndefinePreprocessorDefinitions': 'wer',
+ 'UseFullPaths': 'true',
+ 'WarningLevel': 'Level3',
+ 'WholeProgramOptimization': 'true',
+ 'XMLDocumentationFileName': '$(IntDir)c'},
+ 'Link': {
+ 'AdditionalDependencies': 'zx',
+ 'AdditionalLibraryDirectories': 'asd',
+ 'AdditionalManifestDependencies': 's2',
+ 'AdditionalOptions': '/mor2',
+ 'AddModuleNamesToAssembly': 'd1',
+ 'AllowIsolation': 'false',
+ 'AssemblyDebug': 'true',
+ 'AssemblyLinkResource': 'd5',
+ 'BaseAddress': '23423',
+ 'CLRImageType': 'ForceSafeILImage',
+ 'CLRThreadAttribute': 'MTAThreadingAttribute',
+ 'CLRUnmanagedCodeCheck': 'true',
+ 'DataExecutionPrevention': '',
+ 'DelayLoadDLLs': 'd4',
+ 'DelaySign': 'true',
+ 'Driver': 'UpOnly',
+ 'EmbedManagedResourceFile': 'd2',
+ 'EnableCOMDATFolding': 'false',
+ 'EnableUAC': 'false',
+ 'EntryPointSymbol': 'f5',
+ 'FixedBaseAddress': 'false',
+ 'ForceSymbolReferences': 'd3',
+ 'FunctionOrder': 'fssdfsd',
+ 'GenerateDebugInformation': 'true',
+ 'GenerateMapFile': 'true',
+ 'HeapCommitSize': '13',
+ 'HeapReserveSize': '12',
+ 'IgnoreAllDefaultLibraries': 'true',
+ 'IgnoreEmbeddedIDL': 'true',
+ 'IgnoreSpecificDefaultLibraries': 'flob;flok',
+ 'ImportLibrary': 'f4',
+ 'KeyContainer': 'f7',
+ 'KeyFile': 'f6',
+ 'LargeAddressAware': 'true',
+ 'LinkErrorReporting': 'QueueForNextLogin',
+ 'LinkTimeCodeGeneration': 'UseLinkTimeCodeGeneration',
+ 'ManifestFile': '$(IntDir)$(TargetFileName).2intermediate.manifest',
+ 'MapExports': 'true',
+ 'MapFileName': 'd5',
+ 'MergedIDLBaseFileName': 'f2',
+ 'MergeSections': 'f5',
+ 'MidlCommandFile': 'f1',
+ 'ModuleDefinitionFile': 'sdsd',
+ 'NoEntryPoint': 'true',
+ 'OptimizeReferences': 'true',
+ 'OutputFile': '$(OutDir)$(ProjectName)2.exe',
+ 'PerUserRedirection': 'true',
+ 'Profile': 'true',
+ 'ProfileGuidedDatabase': '$(TargetDir)$(TargetName).pgdd',
+ 'ProgramDatabaseFile': 'Flob.pdb',
+ 'RandomizedBaseAddress': 'false',
+ 'RegisterOutput': 'true',
+ 'SetChecksum': 'false',
+ 'ShowProgress': 'LinkVerbose',
+ 'StackCommitSize': '15',
+ 'StackReserveSize': '14',
+ 'StripPrivateSymbols': 'd3',
+ 'SubSystem': 'Console',
+ 'SupportUnloadOfDelayLoadedDLL': 'true',
+ 'SuppressStartupBanner': 'false',
+ 'SwapRunFromCD': 'true',
+ 'SwapRunFromNET': 'true',
+ 'TargetMachine': 'MachineX86',
+ 'TerminalServerAware': 'false',
+ 'TurnOffAssemblyGeneration': 'true',
+ 'TypeLibraryFile': 'f3',
+ 'TypeLibraryResourceID': '12',
+ 'UACExecutionLevel': 'RequireAdministrator',
+ 'UACUIAccess': 'true',
+ 'Version': '333'},
+ 'ResourceCompile': {
+ 'AdditionalIncludeDirectories': 'f3',
+ 'AdditionalOptions': '/more3',
+ 'Culture': '0x0c0c',
+ 'IgnoreStandardIncludePath': 'true',
+ 'PreprocessorDefinitions': '_UNICODE;UNICODE2',
+ 'ResourceOutputFileName': '$(IntDir)%(Filename)3.res',
+ 'ShowProgress': 'true'},
+ 'Mt': {
+ 'AdditionalManifestFiles': 'sfsdfsd',
+ 'AdditionalOptions': 'afdsdafsd',
+ 'AssemblyIdentity': 'sddfdsadfsa',
+ 'ComponentFileName': 'fsdfds',
+ 'GenerateCatalogFiles': 'true',
+ 'InputResourceManifests': 'asfsfdafs',
+ 'OutputManifestFile': '$(TargetPath).manifestdfs',
+ 'RegistrarScriptFile': 'sdfsfd',
+ 'ReplacementsFile': 'sdffsd',
+ 'SuppressStartupBanner': 'false',
+ 'TypeLibraryFile': 'sfsd',
+ 'UpdateFileHashes': 'true',
+ 'UpdateFileHashesSearchPath': 'sfsd',
+ 'VerboseOutput': 'true'},
+ 'ProjectReference': {
+ 'LinkLibraryDependencies': 'false',
+ 'UseLibraryDependencyInputs': 'true'},
+ '': {
+ 'EmbedManifest': 'false',
+ 'GenerateManifest': 'false',
+ 'IgnoreImportLibrary': 'true',
+ 'LinkIncremental': ''
+ },
+ 'ManifestResourceCompile': {
+ 'ResourceOutputFileName':
+ '$(IntDir)$(TargetFileName).embed.manifest.resfdsf'}
+ }
+ actual_msbuild_settings = MSVSSettings.ConvertToMsBuildSettings(
+ msvs_settings,
+ self.stderr)
+ self.assertEqual(expected_msbuild_settings, actual_msbuild_settings)
+ self._ExpectedWarnings([])
+
+if __name__ == '__main__':
+ unittest.main() \ No newline at end of file
diff --git a/Source/ThirdParty/gyp/pylib/gyp/MSVSToolFile.py b/Source/ThirdParty/gyp/pylib/gyp/MSVSToolFile.py
new file mode 100644
index 000000000..493a9c427
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/MSVSToolFile.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python2.4
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Visual Studio project reader/writer."""
+
+import common
+import xml.dom
+import xml_fix
+
+
+#------------------------------------------------------------------------------
+
+
+class Writer(object):
+ """Visual Studio XML tool file writer."""
+
+ def __init__(self, tool_file_path):
+ """Initializes the tool file.
+
+ Args:
+ tool_file_path: Path to the tool file.
+ """
+ self.tool_file_path = tool_file_path
+ self.doc = None
+
+ def Create(self, name):
+ """Creates the tool file document.
+
+ Args:
+ name: Name of the tool file.
+ """
+ self.name = name
+
+ # Create XML doc
+ xml_impl = xml.dom.getDOMImplementation()
+ self.doc = xml_impl.createDocument(None, 'VisualStudioToolFile', None)
+
+ # Add attributes to root element
+ self.n_root = self.doc.documentElement
+ self.n_root.setAttribute('Version', '8.00')
+ self.n_root.setAttribute('Name', self.name)
+
+ # Add rules section
+ self.n_rules = self.doc.createElement('Rules')
+ self.n_root.appendChild(self.n_rules)
+
+ def AddCustomBuildRule(self, name, cmd, description,
+ additional_dependencies,
+ outputs, extensions):
+ """Adds a rule to the tool file.
+
+ Args:
+ name: Name of the rule.
+ description: Description of the rule.
+ cmd: Command line of the rule.
+ additional_dependencies: other files which may trigger the rule.
+ outputs: outputs of the rule.
+ extensions: extensions handled by the rule.
+ """
+ n_rule = self.doc.createElement('CustomBuildRule')
+ n_rule.setAttribute('Name', name)
+ n_rule.setAttribute('ExecutionDescription', description)
+ n_rule.setAttribute('CommandLine', cmd)
+ n_rule.setAttribute('Outputs', ';'.join(outputs))
+ n_rule.setAttribute('FileExtensions', ';'.join(extensions))
+ n_rule.setAttribute('AdditionalDependencies',
+ ';'.join(additional_dependencies))
+ self.n_rules.appendChild(n_rule)
+
+ def Write(self, writer=common.WriteOnDiff):
+ """Writes the tool file."""
+ f = writer(self.tool_file_path)
+ fix = xml_fix.XmlFix()
+ self.doc.writexml(f, encoding='Windows-1252', addindent=' ', newl='\r\n')
+ fix.Cleanup()
+ f.close()
+
+#------------------------------------------------------------------------------
diff --git a/Source/ThirdParty/gyp/pylib/gyp/MSVSUserFile.py b/Source/ThirdParty/gyp/pylib/gyp/MSVSUserFile.py
new file mode 100644
index 000000000..ba166a92a
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/MSVSUserFile.py
@@ -0,0 +1,182 @@
+#!/usr/bin/python2.4
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Visual Studio user preferences file writer."""
+
+import common
+import os
+import re
+import socket # for gethostname
+import xml.dom
+import xml_fix
+
+
+#------------------------------------------------------------------------------
+
+def _FindCommandInPath(command):
+ """If there are no slashes in the command given, this function
+ searches the PATH env to find the given command, and converts it
+ to an absolute path. We have to do this because MSVS is looking
+ for an actual file to launch a debugger on, not just a command
+ line. Note that this happens at GYP time, so anything needing to
+ be built needs to have a full path."""
+ if '/' in command or '\\' in command:
+ # If the command already has path elements (either relative or
+ # absolute), then assume it is constructed properly.
+ return command
+ else:
+ # Search through the path list and find an existing file that
+ # we can access.
+ paths = os.environ.get('PATH','').split(os.pathsep)
+ for path in paths:
+ item = os.path.join(path, command)
+ if os.path.isfile(item) and os.access(item, os.X_OK):
+ return item
+ return command
+
+def _QuoteWin32CommandLineArgs(args):
+ new_args = []
+ for arg in args:
+ # Replace all double-quotes with double-double-quotes to escape
+ # them for cmd shell, and then quote the whole thing if there
+ # are any.
+ if arg.find('"') != -1:
+ arg = '""'.join(arg.split('"'))
+ arg = '"%s"' % arg
+
+ # Otherwise, if there are any spaces, quote the whole arg.
+ elif re.search(r'[ \t\n]', arg):
+ arg = '"%s"' % arg
+ new_args.append(arg)
+ return new_args
+
+class Writer(object):
+ """Visual Studio XML user user file writer."""
+
+ def __init__(self, user_file_path, version):
+ """Initializes the user file.
+
+ Args:
+ user_file_path: Path to the user file.
+ """
+ self.user_file_path = user_file_path
+ self.version = version
+ self.doc = None
+
+ def Create(self, name):
+ """Creates the user file document.
+
+ Args:
+ name: Name of the user file.
+ """
+ self.name = name
+
+ # Create XML doc
+ xml_impl = xml.dom.getDOMImplementation()
+ self.doc = xml_impl.createDocument(None, 'VisualStudioUserFile', None)
+
+ # Add attributes to root element
+ self.n_root = self.doc.documentElement
+ self.n_root.setAttribute('Version', self.version.ProjectVersion())
+ self.n_root.setAttribute('Name', self.name)
+
+ # Add configurations section
+ self.n_configs = self.doc.createElement('Configurations')
+ self.n_root.appendChild(self.n_configs)
+
+ def _AddConfigToNode(self, parent, config_type, config_name):
+ """Adds a configuration to the parent node.
+
+ Args:
+ parent: Destination node.
+ config_type: Type of configuration node.
+ config_name: Configuration name.
+ """
+ # Add configuration node and its attributes
+ n_config = self.doc.createElement(config_type)
+ n_config.setAttribute('Name', config_name)
+ parent.appendChild(n_config)
+
+ def AddConfig(self, name):
+ """Adds a configuration to the project.
+
+ Args:
+ name: Configuration name.
+ """
+ self._AddConfigToNode(self.n_configs, 'Configuration', name)
+
+
+ def AddDebugSettings(self, config_name, command, environment = {},
+ working_directory=""):
+ """Adds a DebugSettings node to the user file for a particular config.
+
+ Args:
+ command: command line to run. First element in the list is the
+ executable. All elements of the command will be quoted if
+ necessary.
+ working_directory: other files which may trigger the rule. (optional)
+ """
+ command = _QuoteWin32CommandLineArgs(command)
+
+ n_cmd = self.doc.createElement('DebugSettings')
+ abs_command = _FindCommandInPath(command[0])
+ n_cmd.setAttribute('Command', abs_command)
+ n_cmd.setAttribute('WorkingDirectory', working_directory)
+ n_cmd.setAttribute('CommandArguments', " ".join(command[1:]))
+ n_cmd.setAttribute('RemoteMachine', socket.gethostname())
+
+ if environment and isinstance(environment, dict):
+ n_cmd.setAttribute('Environment',
+ " ".join(['%s="%s"' % (key, val)
+ for (key,val) in environment.iteritems()]))
+ else:
+ n_cmd.setAttribute('Environment', '')
+
+ n_cmd.setAttribute('EnvironmentMerge', 'true')
+
+ # Currently these are all "dummy" values that we're just setting
+ # in the default manner that MSVS does it. We could use some of
+ # these to add additional capabilities, I suppose, but they might
+ # not have parity with other platforms then.
+ n_cmd.setAttribute('Attach', 'false')
+ n_cmd.setAttribute('DebuggerType', '3') # 'auto' debugger
+ n_cmd.setAttribute('Remote', '1')
+ n_cmd.setAttribute('RemoteCommand', '')
+ n_cmd.setAttribute('HttpUrl', '')
+ n_cmd.setAttribute('PDBPath', '')
+ n_cmd.setAttribute('SQLDebugging', '')
+ n_cmd.setAttribute('DebuggerFlavor', '0')
+ n_cmd.setAttribute('MPIRunCommand', '')
+ n_cmd.setAttribute('MPIRunArguments', '')
+ n_cmd.setAttribute('MPIRunWorkingDirectory', '')
+ n_cmd.setAttribute('ApplicationCommand', '')
+ n_cmd.setAttribute('ApplicationArguments', '')
+ n_cmd.setAttribute('ShimCommand', '')
+ n_cmd.setAttribute('MPIAcceptMode', '')
+ n_cmd.setAttribute('MPIAcceptFilter', '')
+
+ # Find the config, and add it if it doesn't exist.
+ found = False
+ for config in self.n_configs.childNodes:
+ if config.getAttribute("Name") == config_name:
+ found = True
+
+ if not found:
+ self.AddConfig(config_name)
+
+ # Add the DebugSettings onto the appropriate config.
+ for config in self.n_configs.childNodes:
+ if config.getAttribute("Name") == config_name:
+ config.appendChild(n_cmd)
+ break
+
+ def Write(self, writer=common.WriteOnDiff):
+ """Writes the user file."""
+ f = writer(self.user_file_path)
+ self.doc.writexml(f, encoding='Windows-1252', addindent=' ', newl='\r\n')
+ f.close()
+
+#------------------------------------------------------------------------------
diff --git a/Source/ThirdParty/gyp/pylib/gyp/MSVSVersion.py b/Source/ThirdParty/gyp/pylib/gyp/MSVSVersion.py
new file mode 100755
index 000000000..f206eb6bc
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/MSVSVersion.py
@@ -0,0 +1,200 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Handle version information related to Visual Stuio."""
+
+import os
+import re
+import subprocess
+import sys
+
+
+class VisualStudioVersion:
+ """Information regarding a version of Visual Studio."""
+
+ def __init__(self, short_name, description,
+ solution_version, project_version, flat_sln, uses_vcxproj):
+ self.short_name = short_name
+ self.description = description
+ self.solution_version = solution_version
+ self.project_version = project_version
+ self.flat_sln = flat_sln
+ self.uses_vcxproj = uses_vcxproj
+
+ def ShortName(self):
+ return self.short_name
+
+ def Description(self):
+ """Get the full description of the version."""
+ return self.description
+
+ def SolutionVersion(self):
+ """Get the version number of the sln files."""
+ return self.solution_version
+
+ def ProjectVersion(self):
+ """Get the version number of the vcproj or vcxproj files."""
+ return self.project_version
+
+ def FlatSolution(self):
+ return self.flat_sln
+
+ def UsesVcxproj(self):
+ """Returns true if this version uses a vcxproj file."""
+ return self.uses_vcxproj
+
+ def ProjectExtension(self):
+ """Returns the file extension for the project."""
+ return self.uses_vcxproj and '.vcxproj' or '.vcproj'
+
+def _RegistryGetValue(key, value):
+ """Use reg.exe to read a paricular key.
+
+ While ideally we might use the win32 module, we would like gyp to be
+ python neutral, so for instance cygwin python lacks this module.
+
+ Arguments:
+ key: The registry key to read from.
+ value: The particular value to read.
+ Return:
+ The contents there, or None for failure.
+ """
+ # Skip if not on Windows.
+ if sys.platform not in ('win32', 'cygwin'):
+ return None
+ # Run reg.exe.
+ cmd = [os.path.join(os.environ.get('WINDIR', ''), 'System32', 'reg.exe'),
+ 'query', key, '/v', value]
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ text = p.communicate()[0]
+ # Require a successful return value.
+ if p.returncode:
+ return None
+ # Extract value.
+ match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text)
+ if not match:
+ return None
+ return match.group(1)
+
+
+def _RegistryKeyExists(key):
+ """Use reg.exe to see if a key exists.
+
+ Args:
+ key: The registry key to check.
+ Return:
+ True if the key exists
+ """
+ # Skip if not on Windows.
+ if sys.platform not in ('win32', 'cygwin'):
+ return None
+ # Run reg.exe.
+ cmd = [os.path.join(os.environ.get('WINDIR', ''), 'System32', 'reg.exe'),
+ 'query', key]
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ return p.returncode == 0
+
+
+def _CreateVersion(name):
+ versions = {
+ '2010': VisualStudioVersion('2010',
+ 'Visual Studio 2010',
+ solution_version='11.00',
+ project_version='4.0',
+ flat_sln=False,
+ uses_vcxproj=True),
+ '2008': VisualStudioVersion('2008',
+ 'Visual Studio 2008',
+ solution_version='10.00',
+ project_version='9.00',
+ flat_sln=False,
+ uses_vcxproj=False),
+ '2008e': VisualStudioVersion('2008e',
+ 'Visual Studio 2008',
+ solution_version='10.00',
+ project_version='9.00',
+ flat_sln=True,
+ uses_vcxproj=False),
+ '2005': VisualStudioVersion('2005',
+ 'Visual Studio 2005',
+ solution_version='9.00',
+ project_version='8.00',
+ flat_sln=False,
+ uses_vcxproj=False),
+ '2005e': VisualStudioVersion('2005e',
+ 'Visual Studio 2005',
+ solution_version='9.00',
+ project_version='8.00',
+ flat_sln=True,
+ uses_vcxproj=False),
+ }
+ return versions[str(name)]
+
+
+def _DetectVisualStudioVersions():
+ """Collect the list of installed visual studio versions.
+
+ Returns:
+ A list of visual studio versions installed in descending order of
+ usage preference.
+ Base this on the registry and a quick check if devenv.exe exists.
+ Only versions 8-10 are considered.
+ Possibilities are:
+ 2005 - Visual Studio 2005 (8)
+ 2008 - Visual Studio 2008 (9)
+ 2010 - Visual Studio 2010 (10)
+ """
+ version_to_year = {'8.0': '2005', '9.0': '2008', '10.0': '2010'}
+ versions = []
+ # For now, prefer versions before VS2010
+ for version in ('9.0', '8.0', '10.0'):
+ # Check if VS2010 and later is installed as specified by
+ # http://msdn.microsoft.com/en-us/library/bb164659.aspx
+ key32 = r'HKLM\SOFTWARE\Microsoft\DevDiv\VS\Servicing\%s' % version
+ key64 = r'HKLM\SOFTWARE\Wow6432Node\Microsoft\DevDiv\VS\Servicing\%sD' % (
+ version)
+ if _RegistryKeyExists(key32) or _RegistryKeyExists(key64):
+ # Add this one.
+ # TODO(jeanluc) This does not check for an express version.
+ # TODO(jeanluc) Uncomment this line when ready to support VS2010:
+ # versions.append(_CreateVersion(version_to_year[version]))
+ continue
+ # Get the install dir for this version.
+ key = r'HKLM\Software\Microsoft\VisualStudio\%s' % version
+ path = _RegistryGetValue(key, 'InstallDir')
+ if not path:
+ continue
+ # Check for full.
+ if os.path.exists(os.path.join(path, 'devenv.exe')):
+ # Add this one.
+ versions.append(_CreateVersion(version_to_year[version]))
+ # Check for express.
+ elif os.path.exists(os.path.join(path, 'vcexpress.exe')):
+ # Add this one.
+ versions.append(_CreateVersion(version_to_year[version] + 'e'))
+ return versions
+
+
+def SelectVisualStudioVersion(version='auto'):
+ """Select which version of Visual Studio projects to generate.
+
+ Arguments:
+ version: Hook to allow caller to force a particular version (vs auto).
+ Returns:
+ An object representing a visual studio project format version.
+ """
+ # In auto mode, check environment variable for override.
+ if version == 'auto':
+ version = os.environ.get('GYP_MSVS_VERSION', 'auto')
+ # In auto mode, pick the most preferred version present.
+ if version == 'auto':
+ versions = _DetectVisualStudioVersions()
+ if not versions:
+ # Default to 2005.
+ return _CreateVersion('2005')
+ return versions[0]
+ # Convert version string into a version object.
+ return _CreateVersion(version)
diff --git a/Source/ThirdParty/gyp/pylib/gyp/SCons.py b/Source/ThirdParty/gyp/pylib/gyp/SCons.py
new file mode 100644
index 000000000..9c57bcbfc
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/SCons.py
@@ -0,0 +1,200 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+SCons generator.
+
+This contains class definitions and supporting functions for generating
+pieces of SCons files for the different types of GYP targets.
+"""
+
+import os
+
+
+def WriteList(fp, list, prefix='',
+ separator=',\n ',
+ preamble=None,
+ postamble=None):
+ fp.write(preamble or '')
+ fp.write((separator or ' ').join([prefix + l for l in list]))
+ fp.write(postamble or '')
+
+
+class TargetBase(object):
+ """
+ Base class for a SCons representation of a GYP target.
+ """
+ is_ignored = False
+ target_prefix = ''
+ target_suffix = ''
+ def __init__(self, spec):
+ self.spec = spec
+ def full_product_name(self):
+ """
+ Returns the full name of the product being built:
+
+ * Uses 'product_name' if it's set, else prefix + 'target_name'.
+ * Prepends 'product_dir' if set.
+ * Appends SCons suffix variables for the target type (or
+ product_extension).
+ """
+ suffix = self.target_suffix
+ product_extension = self.spec.get('product_extension')
+ if product_extension:
+ suffix = '.' + product_extension
+ prefix = self.spec.get('product_prefix', self.target_prefix)
+ name = self.spec['target_name']
+ name = prefix + self.spec.get('product_name', name) + suffix
+ product_dir = self.spec.get('product_dir')
+ if product_dir:
+ name = os.path.join(product_dir, name)
+ else:
+ name = os.path.join(self.out_dir, name)
+ return name
+
+ def write_input_files(self, fp):
+ """
+ Writes the definition of the input files (sources).
+ """
+ sources = self.spec.get('sources')
+ if not sources:
+ fp.write('\ninput_files = []\n')
+ return
+ preamble = '\ninput_files = [\n '
+ postamble = ',\n]\n'
+ WriteList(fp, map(repr, sources), preamble=preamble, postamble=postamble)
+
+ def builder_call(self):
+ """
+ Returns the actual SCons builder call to build this target.
+ """
+ name = self.full_product_name()
+ return 'env.%s(env.File(%r), input_files)' % (self.builder_name, name)
+ def write_target(self, fp, src_dir='', pre=''):
+ """
+ Writes the lines necessary to build this target.
+ """
+ fp.write('\n' + pre)
+ fp.write('_outputs = %s\n' % self.builder_call())
+ fp.write('target_files.extend(_outputs)\n')
+
+
+class NoneTarget(TargetBase):
+ """
+ A GYP target type of 'none', implicitly or explicitly.
+ """
+ def write_target(self, fp, pre=''):
+ fp.write('\ntarget_files.extend(input_files)\n')
+
+
+class SettingsTarget(TargetBase):
+ """
+ A GYP target type of 'settings'.
+ """
+ is_ignored = True
+
+
+compilable_sources_template = """
+_result = []
+for infile in input_files:
+ if env.compilable(infile):
+ if (type(infile) == type('')
+ and (infile.startswith(%(src_dir)r)
+ or not os.path.isabs(env.subst(infile)))):
+ # Force files below the build directory by replacing all '..'
+ # elements in the path with '__':
+ base, ext = os.path.splitext(os.path.normpath(infile))
+ base = [d == '..' and '__' or d for d in base.split('/')]
+ base = os.path.join(*base)
+ object = '${OBJ_DIR}/${COMPONENT_NAME}/${TARGET_NAME}/' + base
+ if not infile.startswith(%(src_dir)r):
+ infile = %(src_dir)r + infile
+ infile = env.%(name)s(object, infile)[0]
+ else:
+ infile = env.%(name)s(infile)[0]
+ _result.append(infile)
+input_files = _result
+"""
+
+class CompilableSourcesTargetBase(TargetBase):
+ """
+ An abstract base class for targets that compile their source files.
+
+ We explicitly transform compilable files into object files,
+ even though SCons could infer that for us, because we want
+ to control where the object file ends up. (The implicit rules
+ in SCons always put the object file next to the source file.)
+ """
+ intermediate_builder_name = None
+ def write_target(self, fp, src_dir='', pre=''):
+ if self.intermediate_builder_name is None:
+ raise NotImplementedError
+ if src_dir and not src_dir.endswith('/'):
+ src_dir += '/'
+ variables = {
+ 'src_dir': src_dir,
+ 'name': self.intermediate_builder_name,
+ }
+ fp.write(compilable_sources_template % variables)
+ super(CompilableSourcesTargetBase, self).write_target(fp)
+
+
+class ProgramTarget(CompilableSourcesTargetBase):
+ """
+ A GYP target type of 'executable'.
+ """
+ builder_name = 'GypProgram'
+ intermediate_builder_name = 'StaticObject'
+ target_prefix = '${PROGPREFIX}'
+ target_suffix = '${PROGSUFFIX}'
+ out_dir = '${TOP_BUILDDIR}'
+
+
+class StaticLibraryTarget(CompilableSourcesTargetBase):
+ """
+ A GYP target type of 'static_library'.
+ """
+ builder_name = 'GypStaticLibrary'
+ intermediate_builder_name = 'StaticObject'
+ target_prefix = '${LIBPREFIX}'
+ target_suffix = '${LIBSUFFIX}'
+ out_dir = '${LIB_DIR}'
+
+
+class SharedLibraryTarget(CompilableSourcesTargetBase):
+ """
+ A GYP target type of 'shared_library'.
+ """
+ builder_name = 'GypSharedLibrary'
+ intermediate_builder_name = 'SharedObject'
+ target_prefix = '${SHLIBPREFIX}'
+ target_suffix = '${SHLIBSUFFIX}'
+ out_dir = '${LIB_DIR}'
+
+
+class LoadableModuleTarget(CompilableSourcesTargetBase):
+ """
+ A GYP target type of 'loadable_module'.
+ """
+ builder_name = 'GypLoadableModule'
+ intermediate_builder_name = 'SharedObject'
+ target_prefix = '${SHLIBPREFIX}'
+ target_suffix = '${SHLIBSUFFIX}'
+ out_dir = '${TOP_BUILDDIR}'
+
+
+TargetMap = {
+ None : NoneTarget,
+ 'none' : NoneTarget,
+ 'settings' : SettingsTarget,
+ 'executable' : ProgramTarget,
+ 'static_library' : StaticLibraryTarget,
+ 'shared_library' : SharedLibraryTarget,
+ 'loadable_module' : LoadableModuleTarget,
+}
+
+def Target(spec):
+ return TargetMap[spec.get('type')](spec)
diff --git a/Source/ThirdParty/gyp/pylib/gyp/__init__.py b/Source/ThirdParty/gyp/pylib/gyp/__init__.py
new file mode 100644
index 000000000..4b088f620
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/__init__.py
@@ -0,0 +1,461 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import copy
+import gyp.input
+import optparse
+import os.path
+import re
+import shlex
+import sys
+
+# Default debug modes for GYP
+debug = {}
+
+# List of "official" debug modes, but you can use anything you like.
+DEBUG_GENERAL = 'general'
+DEBUG_VARIABLES = 'variables'
+DEBUG_INCLUDES = 'includes'
+
+def DebugOutput(mode, message):
+ if mode in gyp.debug.keys():
+ print "%s: %s" % (mode.upper(), message)
+
+def FindBuildFiles():
+ extension = '.gyp'
+ files = os.listdir(os.getcwd())
+ build_files = []
+ for file in files:
+ if file[-len(extension):] == extension:
+ build_files.append(file)
+ return build_files
+
+
+def Load(build_files, format, default_variables={},
+ includes=[], depth='.', params={}, check=False, circular_check=True):
+ """
+ Loads one or more specified build files.
+ default_variables and includes will be copied before use.
+ Returns the generator for the specified format and the
+ data returned by loading the specified build files.
+ """
+ default_variables = copy.copy(default_variables)
+
+ # Default variables provided by this program and its modules should be
+ # named WITH_CAPITAL_LETTERS to provide a distinct "best practice" namespace,
+ # avoiding collisions with user and automatic variables.
+ default_variables['GENERATOR'] = format
+
+ generator_name = 'gyp.generator.' + format
+ # These parameters are passed in order (as opposed to by key)
+ # because ActivePython cannot handle key parameters to __import__.
+ generator = __import__(generator_name, globals(), locals(), generator_name)
+ for (key, val) in generator.generator_default_variables.items():
+ default_variables.setdefault(key, val)
+
+ # Give the generator the opportunity to set additional variables based on
+ # the params it will receive in the output phase.
+ if getattr(generator, 'CalculateVariables', None):
+ generator.CalculateVariables(default_variables, params)
+
+ # Fetch the generator specific info that gets fed to input, we use getattr
+ # so we can default things and the generators only have to provide what
+ # they need.
+ generator_input_info = {
+ 'generator_wants_absolute_build_file_paths':
+ getattr(generator, 'generator_wants_absolute_build_file_paths', False),
+ 'generator_handles_variants':
+ getattr(generator, 'generator_handles_variants', False),
+ 'non_configuration_keys':
+ getattr(generator, 'generator_additional_non_configuration_keys', []),
+ 'path_sections':
+ getattr(generator, 'generator_additional_path_sections', []),
+ 'extra_sources_for_rules':
+ getattr(generator, 'generator_extra_sources_for_rules', []),
+ 'generator_supports_multiple_toolsets':
+ getattr(generator, 'generator_supports_multiple_toolsets', False),
+ }
+
+ # Process the input specific to this generator.
+ result = gyp.input.Load(build_files, default_variables, includes[:],
+ depth, generator_input_info, check, circular_check)
+ return [generator] + result
+
+def NameValueListToDict(name_value_list):
+ """
+ Takes an array of strings of the form 'NAME=VALUE' and creates a dictionary
+ of the pairs. If a string is simply NAME, then the value in the dictionary
+ is set to True. If VALUE can be converted to an integer, it is.
+ """
+ result = { }
+ for item in name_value_list:
+ tokens = item.split('=', 1)
+ if len(tokens) == 2:
+ # If we can make it an int, use that, otherwise, use the string.
+ try:
+ token_value = int(tokens[1])
+ except ValueError:
+ token_value = tokens[1]
+ # Set the variable to the supplied value.
+ result[tokens[0]] = token_value
+ else:
+ # No value supplied, treat it as a boolean and set it.
+ result[tokens[0]] = True
+ return result
+
+def ShlexEnv(env_name):
+ flags = os.environ.get(env_name, [])
+ if flags:
+ flags = shlex.split(flags)
+ return flags
+
+def FormatOpt(opt, value):
+ if opt.startswith('--'):
+ return '%s=%s' % (opt, value)
+ return opt + value
+
+def RegenerateAppendFlag(flag, values, predicate, env_name, options):
+ """Regenerate a list of command line flags, for an option of action='append'.
+
+ The |env_name|, if given, is checked in the environment and used to generate
+ an initial list of options, then the options that were specified on the
+ command line (given in |values|) are appended. This matches the handling of
+ environment variables and command line flags where command line flags override
+ the environment, while not requiring the environment to be set when the flags
+ are used again.
+ """
+ flags = []
+ if options.use_environment and env_name:
+ for flag_value in ShlexEnv(env_name):
+ flags.append(FormatOpt(flag, predicate(flag_value)))
+ if values:
+ for flag_value in values:
+ flags.append(FormatOpt(flag, predicate(flag_value)))
+ return flags
+
+def RegenerateFlags(options):
+ """Given a parsed options object, and taking the environment variables into
+ account, returns a list of flags that should regenerate an equivalent options
+ object (even in the absence of the environment variables.)
+
+ Any path options will be normalized relative to depth.
+
+ The format flag is not included, as it is assumed the calling generator will
+ set that as appropriate.
+ """
+ def FixPath(path):
+ path = gyp.common.FixIfRelativePath(path, options.depth)
+ if not path:
+ return os.path.curdir
+ return path
+
+ def Noop(value):
+ return value
+
+ # We always want to ignore the environment when regenerating, to avoid
+ # duplicate or changed flags in the environment at the time of regeneration.
+ flags = ['--ignore-environment']
+ for name, metadata in options._regeneration_metadata.iteritems():
+ opt = metadata['opt']
+ value = getattr(options, name)
+ value_predicate = metadata['type'] == 'path' and FixPath or Noop
+ action = metadata['action']
+ env_name = metadata['env_name']
+ if action == 'append':
+ flags.extend(RegenerateAppendFlag(opt, value, value_predicate,
+ env_name, options))
+ elif action in ('store', None): # None is a synonym for 'store'.
+ if value:
+ flags.append(FormatOpt(opt, value_predicate(value)))
+ elif options.use_environment and env_name and os.environ.get(env_name):
+ flags.append(FormatOpt(opt, value_predicate(os.environ.get(env_name))))
+ elif action in ('store_true', 'store_false'):
+ if ((action == 'store_true' and value) or
+ (action == 'store_false' and not value)):
+ flags.append(opt)
+ elif options.use_environment and env_name:
+ print >>sys.stderr, ('Warning: environment regeneration unimplemented '
+ 'for %s flag %r env_name %r' % (action, opt,
+ env_name))
+ else:
+ print >>sys.stderr, ('Warning: regeneration unimplemented for action %r '
+ 'flag %r' % (action, opt))
+
+ return flags
+
+class RegeneratableOptionParser(optparse.OptionParser):
+ def __init__(self):
+ self.__regeneratable_options = {}
+ optparse.OptionParser.__init__(self)
+
+ def add_option(self, *args, **kw):
+ """Add an option to the parser.
+
+ This accepts the same arguments as OptionParser.add_option, plus the
+ following:
+ regenerate: can be set to False to prevent this option from being included
+ in regeneration.
+ env_name: name of environment variable that additional values for this
+ option come from.
+ type: adds type='path', to tell the regenerator that the values of
+ this option need to be made relative to options.depth
+ """
+ env_name = kw.pop('env_name', None)
+ if 'dest' in kw and kw.pop('regenerate', True):
+ dest = kw['dest']
+
+ # The path type is needed for regenerating, for optparse we can just treat
+ # it as a string.
+ type = kw.get('type')
+ if type == 'path':
+ kw['type'] = 'string'
+
+ self.__regeneratable_options[dest] = {
+ 'action': kw.get('action'),
+ 'type': type,
+ 'env_name': env_name,
+ 'opt': args[0],
+ }
+
+ optparse.OptionParser.add_option(self, *args, **kw)
+
+ def parse_args(self, *args):
+ values, args = optparse.OptionParser.parse_args(self, *args)
+ values._regeneration_metadata = self.__regeneratable_options
+ return values, args
+
+def main(args):
+ my_name = os.path.basename(sys.argv[0])
+
+ parser = RegeneratableOptionParser()
+ usage = 'usage: %s [options ...] [build_file ...]'
+ parser.set_usage(usage.replace('%s', '%prog'))
+ parser.add_option('-D', dest='defines', action='append', metavar='VAR=VAL',
+ env_name='GYP_DEFINES',
+ help='sets variable VAR to value VAL')
+ parser.add_option('-f', '--format', dest='formats', action='append',
+ env_name='GYP_GENERATORS', regenerate=False,
+ help='output formats to generate')
+ parser.add_option('--msvs-version', dest='msvs_version',
+ regenerate=False,
+ help='Deprecated; use -G msvs_version=MSVS_VERSION instead')
+ parser.add_option('-I', '--include', dest='includes', action='append',
+ metavar='INCLUDE', type='path',
+ help='files to include in all loaded .gyp files')
+ parser.add_option('--depth', dest='depth', metavar='PATH', type='path',
+ help='set DEPTH gyp variable to a relative path to PATH')
+ parser.add_option('-d', '--debug', dest='debug', metavar='DEBUGMODE',
+ action='append', default=[], help='turn on a debugging '
+ 'mode for debugging GYP. Supported modes are "variables" '
+ 'and "general"')
+ parser.add_option('-S', '--suffix', dest='suffix', default='',
+ help='suffix to add to generated files')
+ parser.add_option('-G', dest='generator_flags', action='append', default=[],
+ metavar='FLAG=VAL', env_name='GYP_GENERATOR_FLAGS',
+ help='sets generator flag FLAG to VAL')
+ parser.add_option('--generator-output', dest='generator_output',
+ action='store', default=None, metavar='DIR', type='path',
+ env_name='GYP_GENERATOR_OUTPUT',
+ help='puts generated build files under DIR')
+ parser.add_option('--ignore-environment', dest='use_environment',
+ action='store_false', default=True, regenerate=False,
+ help='do not read options from environment variables')
+ parser.add_option('--check', dest='check', action='store_true',
+ help='check format of gyp files')
+ parser.add_option('--toplevel-dir', dest='toplevel_dir', action='store',
+ default=None, metavar='DIR', type='path',
+ help='directory to use as the root of the source tree')
+ # --no-circular-check disables the check for circular relationships between
+ # .gyp files. These relationships should not exist, but they've only been
+ # observed to be harmful with the Xcode generator. Chromium's .gyp files
+ # currently have some circular relationships on non-Mac platforms, so this
+ # option allows the strict behavior to be used on Macs and the lenient
+ # behavior to be used elsewhere.
+ # TODO(mark): Remove this option when http://crbug.com/35878 is fixed.
+ parser.add_option('--no-circular-check', dest='circular_check',
+ action='store_false', default=True, regenerate=False,
+ help="don't check for circular relationships between files")
+
+ # We read a few things from ~/.gyp, so set up a var for that.
+ home_vars = ['HOME']
+ if sys.platform in ('cygwin', 'win32'):
+ home_vars.append('USERPROFILE')
+ home = None
+ home_dot_gyp = None
+ for home_var in home_vars:
+ home = os.getenv(home_var)
+ if home != None:
+ home_dot_gyp = os.path.join(home, '.gyp')
+ if not os.path.exists(home_dot_gyp):
+ home_dot_gyp = None
+ else:
+ break
+
+ # TODO(thomasvl): add support for ~/.gyp/defaults
+
+ options, build_files_arg = parser.parse_args(args)
+ build_files = build_files_arg
+
+ if not options.formats:
+ # If no format was given on the command line, then check the env variable.
+ generate_formats = []
+ if options.use_environment:
+ generate_formats = os.environ.get('GYP_GENERATORS', [])
+ if generate_formats:
+ generate_formats = re.split('[\s,]', generate_formats)
+ if generate_formats:
+ options.formats = generate_formats
+ else:
+ # Nothing in the variable, default based on platform.
+ options.formats = [ {'darwin': 'xcode',
+ 'win32': 'msvs',
+ 'cygwin': 'msvs',
+ 'freebsd7': 'make',
+ 'freebsd8': 'make',
+ 'linux2': 'make',
+ 'openbsd4': 'make',
+ 'sunos5': 'make',}[sys.platform] ]
+
+ if not options.generator_output and options.use_environment:
+ g_o = os.environ.get('GYP_GENERATOR_OUTPUT')
+ if g_o:
+ options.generator_output = g_o
+
+ for mode in options.debug:
+ gyp.debug[mode] = 1
+
+ # Do an extra check to avoid work when we're not debugging.
+ if DEBUG_GENERAL in gyp.debug.keys():
+ DebugOutput(DEBUG_GENERAL, 'running with these options:')
+ for option, value in sorted(options.__dict__.items()):
+ if option[0] == '_':
+ continue
+ if isinstance(value, basestring):
+ DebugOutput(DEBUG_GENERAL, " %s: '%s'" % (option, value))
+ else:
+ DebugOutput(DEBUG_GENERAL, " %s: %s" % (option, str(value)))
+
+ if not build_files:
+ build_files = FindBuildFiles()
+ if not build_files:
+ print >>sys.stderr, (usage + '\n\n%s: error: no build_file') % \
+ (my_name, my_name)
+ return 1
+
+ # TODO(mark): Chromium-specific hack!
+ # For Chromium, the gyp "depth" variable should always be a relative path
+ # to Chromium's top-level "src" directory. If no depth variable was set
+ # on the command line, try to find a "src" directory by looking at the
+ # absolute path to each build file's directory. The first "src" component
+ # found will be treated as though it were the path used for --depth.
+ if not options.depth:
+ for build_file in build_files:
+ build_file_dir = os.path.abspath(os.path.dirname(build_file))
+ build_file_dir_components = build_file_dir.split(os.path.sep)
+ components_len = len(build_file_dir_components)
+ for index in xrange(components_len - 1, -1, -1):
+ if build_file_dir_components[index] == 'src':
+ options.depth = os.path.sep.join(build_file_dir_components)
+ break
+ del build_file_dir_components[index]
+
+ # If the inner loop found something, break without advancing to another
+ # build file.
+ if options.depth:
+ break
+
+ if not options.depth:
+ raise Exception, \
+ 'Could not automatically locate src directory. This is a ' + \
+ 'temporary Chromium feature that will be removed. Use ' + \
+ '--depth as a workaround.'
+
+ # If toplevel-dir is not set, we assume that depth is the root of our source
+ # tree.
+ if not options.toplevel_dir:
+ options.toplevel_dir = options.depth
+
+ # -D on the command line sets variable defaults - D isn't just for define,
+ # it's for default. Perhaps there should be a way to force (-F?) a
+ # variable's value so that it can't be overridden by anything else.
+ cmdline_default_variables = {}
+ defines = []
+ if options.use_environment:
+ defines += ShlexEnv('GYP_DEFINES')
+ if options.defines:
+ defines += options.defines
+ cmdline_default_variables = NameValueListToDict(defines)
+ if DEBUG_GENERAL in gyp.debug.keys():
+ DebugOutput(DEBUG_GENERAL,
+ "cmdline_default_variables: %s" % cmdline_default_variables)
+
+ # Set up includes.
+ includes = []
+
+ # If ~/.gyp/include.gypi exists, it'll be forcibly included into every
+ # .gyp file that's loaded, before anything else is included.
+ if home_dot_gyp != None:
+ default_include = os.path.join(home_dot_gyp, 'include.gypi')
+ if os.path.exists(default_include):
+ includes.append(default_include)
+
+ # Command-line --include files come after the default include.
+ if options.includes:
+ includes.extend(options.includes)
+
+ # Generator flags should be prefixed with the target generator since they
+ # are global across all generator runs.
+ gen_flags = []
+ if options.use_environment:
+ gen_flags += ShlexEnv('GYP_GENERATOR_FLAGS')
+ if options.generator_flags:
+ gen_flags += options.generator_flags
+ generator_flags = NameValueListToDict(gen_flags)
+ if DEBUG_GENERAL in gyp.debug.keys():
+ DebugOutput(DEBUG_GENERAL, "generator_flags: %s" % generator_flags)
+
+ # TODO: Remove this and the option after we've gotten folks to move to the
+ # generator flag.
+ if options.msvs_version:
+ print >>sys.stderr, \
+ 'DEPRECATED: Use generator flag (-G msvs_version=' + \
+ options.msvs_version + ') instead of --msvs-version=' + \
+ options.msvs_version
+ generator_flags['msvs_version'] = options.msvs_version
+
+ # Generate all requested formats (use a set in case we got one format request
+ # twice)
+ for format in set(options.formats):
+ params = {'options': options,
+ 'build_files': build_files,
+ 'generator_flags': generator_flags,
+ 'cwd': os.getcwd(),
+ 'build_files_arg': build_files_arg,
+ 'gyp_binary': sys.argv[0],
+ 'home_dot_gyp': home_dot_gyp}
+
+ # Start with the default variables from the command line.
+ [generator, flat_list, targets, data] = Load(build_files, format,
+ cmdline_default_variables,
+ includes, options.depth,
+ params, options.check,
+ options.circular_check)
+
+ # TODO(mark): Pass |data| for now because the generator needs a list of
+ # build files that came in. In the future, maybe it should just accept
+ # a list, and not the whole data dict.
+ # NOTE: flat_list is the flattened dependency graph specifying the order
+ # that targets may be built. Build systems that operate serially or that
+ # need to have dependencies defined before dependents reference them should
+ # generate targets in the order specified in flat_list.
+ generator.GenerateOutput(flat_list, targets, data, params)
+
+ # Done
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/Source/ThirdParty/gyp/pylib/gyp/common.py b/Source/ThirdParty/gyp/pylib/gyp/common.py
new file mode 100644
index 000000000..bae3ae7e6
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/common.py
@@ -0,0 +1,345 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import errno
+import filecmp
+import os.path
+import re
+import tempfile
+import sys
+
+def ExceptionAppend(e, msg):
+ """Append a message to the given exception's message."""
+ if not e.args:
+ e.args = (msg,)
+ elif len(e.args) == 1:
+ e.args = (str(e.args[0]) + ' ' + msg,)
+ else:
+ e.args = (str(e.args[0]) + ' ' + msg,) + e.args[1:]
+
+
+def ParseQualifiedTarget(target):
+ # Splits a qualified target into a build file, target name and toolset.
+
+ # NOTE: rsplit is used to disambiguate the Windows drive letter separator.
+ target_split = target.rsplit(':', 1)
+ if len(target_split) == 2:
+ [build_file, target] = target_split
+ else:
+ build_file = None
+
+ target_split = target.rsplit('#', 1)
+ if len(target_split) == 2:
+ [target, toolset] = target_split
+ else:
+ toolset = None
+
+ return [build_file, target, toolset]
+
+
+def ResolveTarget(build_file, target, toolset):
+ # This function resolves a target into a canonical form:
+ # - a fully defined build file, either absolute or relative to the current
+ # directory
+ # - a target name
+ # - a toolset
+ #
+ # build_file is the file relative to which 'target' is defined.
+ # target is the qualified target.
+ # toolset is the default toolset for that target.
+ [parsed_build_file, target, parsed_toolset] = ParseQualifiedTarget(target)
+
+ if parsed_build_file:
+ if build_file:
+ # If a relative path, parsed_build_file is relative to the directory
+ # containing build_file. If build_file is not in the current directory,
+ # parsed_build_file is not a usable path as-is. Resolve it by
+ # interpreting it as relative to build_file. If parsed_build_file is
+ # absolute, it is usable as a path regardless of the current directory,
+ # and os.path.join will return it as-is.
+ build_file = os.path.normpath(os.path.join(os.path.dirname(build_file),
+ parsed_build_file))
+ else:
+ build_file = parsed_build_file
+
+ if parsed_toolset:
+ toolset = parsed_toolset
+
+ return [build_file, target, toolset]
+
+
+def BuildFile(fully_qualified_target):
+ # Extracts the build file from the fully qualified target.
+ return ParseQualifiedTarget(fully_qualified_target)[0]
+
+
+def QualifiedTarget(build_file, target, toolset):
+ # "Qualified" means the file that a target was defined in and the target
+ # name, separated by a colon, suffixed by a # and the toolset name:
+ # /path/to/file.gyp:target_name#toolset
+ fully_qualified = build_file + ':' + target
+ if toolset:
+ fully_qualified = fully_qualified + '#' + toolset
+ return fully_qualified
+
+
+def RelativePath(path, relative_to):
+ # Assuming both |path| and |relative_to| are relative to the current
+ # directory, returns a relative path that identifies path relative to
+ # relative_to.
+
+ # Convert to absolute (and therefore normalized paths).
+ path = os.path.abspath(path)
+ relative_to = os.path.abspath(relative_to)
+
+ # Split the paths into components.
+ path_split = path.split(os.path.sep)
+ relative_to_split = relative_to.split(os.path.sep)
+
+ # Determine how much of the prefix the two paths share.
+ prefix_len = len(os.path.commonprefix([path_split, relative_to_split]))
+
+ # Put enough ".." components to back up out of relative_to to the common
+ # prefix, and then append the part of path_split after the common prefix.
+ relative_split = [os.path.pardir] * (len(relative_to_split) - prefix_len) + \
+ path_split[prefix_len:]
+
+ if len(relative_split) == 0:
+ # The paths were the same.
+ return ''
+
+ # Turn it back into a string and we're done.
+ return os.path.join(*relative_split)
+
+
+def FixIfRelativePath(path, relative_to):
+ # Like RelativePath but returns |path| unchanged if it is absolute.
+ if os.path.isabs(path):
+ return path
+ return RelativePath(path, relative_to)
+
+
+def UnrelativePath(path, relative_to):
+ # Assuming that |relative_to| is relative to the current directory, and |path|
+ # is a path relative to the dirname of |relative_to|, returns a path that
+ # identifies |path| relative to the current directory.
+ rel_dir = os.path.dirname(relative_to)
+ return os.path.normpath(os.path.join(rel_dir, path))
+
+
+# re objects used by EncodePOSIXShellArgument. See IEEE 1003.1 XCU.2.2 at
+# http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_02
+# and the documentation for various shells.
+
+# _quote is a pattern that should match any argument that needs to be quoted
+# with double-quotes by EncodePOSIXShellArgument. It matches the following
+# characters appearing anywhere in an argument:
+# \t, \n, space parameter separators
+# # comments
+# $ expansions (quoted to always expand within one argument)
+# % called out by IEEE 1003.1 XCU.2.2
+# & job control
+# ' quoting
+# (, ) subshell execution
+# *, ?, [ pathname expansion
+# ; command delimiter
+# <, >, | redirection
+# = assignment
+# {, } brace expansion (bash)
+# ~ tilde expansion
+# It also matches the empty string, because "" (or '') is the only way to
+# represent an empty string literal argument to a POSIX shell.
+#
+# This does not match the characters in _escape, because those need to be
+# backslash-escaped regardless of whether they appear in a double-quoted
+# string.
+_quote = re.compile('[\t\n #$%&\'()*;<=>?[{|}~]|^$')
+
+# _escape is a pattern that should match any character that needs to be
+# escaped with a backslash, whether or not the argument matched the _quote
+# pattern. _escape is used with re.sub to backslash anything in _escape's
+# first match group, hence the (parentheses) in the regular expression.
+#
+# _escape matches the following characters appearing anywhere in an argument:
+# " to prevent POSIX shells from interpreting this character for quoting
+# \ to prevent POSIX shells from interpreting this character for escaping
+# ` to prevent POSIX shells from interpreting this character for command
+# substitution
+# Missing from this list is $, because the desired behavior of
+# EncodePOSIXShellArgument is to permit parameter (variable) expansion.
+#
+# Also missing from this list is !, which bash will interpret as the history
+# expansion character when history is enabled. bash does not enable history
+# by default in non-interactive shells, so this is not thought to be a problem.
+# ! was omitted from this list because bash interprets "\!" as a literal string
+# including the backslash character (avoiding history expansion but retaining
+# the backslash), which would not be correct for argument encoding. Handling
+# this case properly would also be problematic because bash allows the history
+# character to be changed with the histchars shell variable. Fortunately,
+# as history is not enabled in non-interactive shells and
+# EncodePOSIXShellArgument is only expected to encode for non-interactive
+# shells, there is no room for error here by ignoring !.
+_escape = re.compile(r'(["\\`])')
+
+def EncodePOSIXShellArgument(argument):
+ """Encodes |argument| suitably for consumption by POSIX shells.
+
+ argument may be quoted and escaped as necessary to ensure that POSIX shells
+ treat the returned value as a literal representing the argument passed to
+ this function. Parameter (variable) expansions beginning with $ are allowed
+ to remain intact without escaping the $, to allow the argument to contain
+ references to variables to be expanded by the shell.
+ """
+
+ if not isinstance(argument, str):
+ argument = str(argument)
+
+ if _quote.search(argument):
+ quote = '"'
+ else:
+ quote = ''
+
+ encoded = quote + re.sub(_escape, r'\\\1', argument) + quote
+
+ return encoded
+
+
+def EncodePOSIXShellList(list):
+ """Encodes |list| suitably for consumption by POSIX shells.
+
+ Returns EncodePOSIXShellArgument for each item in list, and joins them
+ together using the space character as an argument separator.
+ """
+
+ encoded_arguments = []
+ for argument in list:
+ encoded_arguments.append(EncodePOSIXShellArgument(argument))
+ return ' '.join(encoded_arguments)
+
+
+def DeepDependencyTargets(target_dicts, roots):
+ """Returns the recursive list of target dependencies."""
+ dependencies = set()
+ pending = set(roots)
+ while pending:
+ # Pluck out one.
+ r = pending.pop()
+ # Skip if visited already.
+ if r in dependencies:
+ continue
+ # Add it.
+ dependencies.add(r)
+ # Add its children.
+ spec = target_dicts[r]
+ pending.update(set(spec.get('dependencies', [])))
+ pending.update(set(spec.get('dependencies_original', [])))
+ return list(dependencies - set(roots))
+
+
+def BuildFileTargets(target_list, build_file):
+ """From a target_list, returns the subset from the specified build_file.
+ """
+ return [p for p in target_list if BuildFile(p) == build_file]
+
+
+def AllTargets(target_list, target_dicts, build_file):
+ """Returns all targets (direct and dependencies) for the specified build_file.
+ """
+ bftargets = BuildFileTargets(target_list, build_file)
+ deptargets = DeepDependencyTargets(target_dicts, bftargets)
+ return bftargets + deptargets
+
+
+def WriteOnDiff(filename):
+ """Write to a file only if the new contents differ.
+
+ Arguments:
+ filename: name of the file to potentially write to.
+ Returns:
+ A file like object which will write to temporary file and only overwrite
+ the target if it differs (on close).
+ """
+
+ class Writer:
+ """Wrapper around file which only covers the target if it differs."""
+ def __init__(self):
+ # Pick temporary file.
+ tmp_fd, self.tmp_path = tempfile.mkstemp(
+ suffix='.tmp',
+ prefix=os.path.split(filename)[1] + '.gyp.',
+ dir=os.path.split(filename)[0])
+ try:
+ self.tmp_file = os.fdopen(tmp_fd, 'wb')
+ except Exception:
+ # Don't leave turds behind.
+ os.unlink(self.tmp_path)
+ raise
+
+ def __getattr__(self, attrname):
+ # Delegate everything else to self.tmp_file
+ return getattr(self.tmp_file, attrname)
+
+ def close(self):
+ try:
+ # Close tmp file.
+ self.tmp_file.close()
+ # Determine if different.
+ same = False
+ try:
+ same = filecmp.cmp(self.tmp_path, filename, False)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+
+ if same:
+ # The new file is identical to the old one, just get rid of the new
+ # one.
+ os.unlink(self.tmp_path)
+ else:
+ # The new file is different from the old one, or there is no old one.
+ # Rename the new file to the permanent name.
+ #
+ # tempfile.mkstemp uses an overly restrictive mode, resulting in a
+ # file that can only be read by the owner, regardless of the umask.
+ # There's no reason to not respect the umask here, which means that
+ # an extra hoop is required to fetch it and reset the new file's mode.
+ #
+ # No way to get the umask without setting a new one? Set a safe one
+ # and then set it back to the old value.
+ umask = os.umask(077)
+ os.umask(umask)
+ os.chmod(self.tmp_path, 0666 & ~umask)
+ if sys.platform == 'win32' and os.path.exists(filename):
+ # NOTE: on windows (but not cygwin) rename will not replace an
+ # existing file, so it must be preceded with a remove. Sadly there
+ # is no way to make the switch atomic.
+ os.remove(filename)
+ os.rename(self.tmp_path, filename)
+ except Exception:
+ # Don't leave turds behind.
+ os.unlink(self.tmp_path)
+ raise
+
+ return Writer()
+
+
+# From Alex Martelli,
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52560
+# ASPN: Python Cookbook: Remove duplicates from a sequence
+# First comment, dated 2001/10/13.
+# (Also in the printed Python Cookbook.)
+
+def uniquer(seq, idfun=None):
+ if idfun is None:
+ def idfun(x): return x
+ seen = {}
+ result = []
+ for item in seq:
+ marker = idfun(item)
+ if marker in seen: continue
+ seen[marker] = 1
+ result.append(item)
+ return result
diff --git a/Source/ThirdParty/gyp/pylib/gyp/easy_xml.py b/Source/ThirdParty/gyp/pylib/gyp/easy_xml.py
new file mode 100644
index 000000000..98e2923a1
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/easy_xml.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import xml.dom
+import xml_fix
+import common
+
+class EasyXml(object):
+ """ Class to easily create XML files with substantial pre-defined structures.
+
+ Visual Studio files have a lot of pre-defined structures. This class makes
+ it easy to represent these structures as Python data structures, instead of
+ having to create a lot of function calls.
+
+ For this class, an XML element is represented as a list composed of:
+ 1. The name of the element, a string,
+ 2. The attributes of the element, an dictionary (optional), and
+ 3+. The content of the element, if any. Strings are simple text nodes and
+ lists are child elements.
+
+ Example 1:
+ <test/>
+ becomes
+ ['test']
+
+ Example 2:
+ <myelement a='value1' b='value2'>
+ <childtype>This is</childtype>
+ <childtype>it!</childtype>
+ </myelement>
+
+ becomes
+ ['myelement', {'a':'value1', 'b':'value2'},
+ ['childtype', 'This is'],
+ ['childtype', 'it!'],
+ ]
+ """
+
+ def __init__(self, name, attributes=None):
+ """ Constructs an object representing an XML document.
+
+ Args:
+ name: A string, the name of the root element.
+ attributes: A dictionary, the attributes of the root.
+ """
+ xml_impl = xml.dom.getDOMImplementation()
+ self.doc = xml_impl.createDocument(None, name, None)
+ if attributes:
+ self.SetAttributes(self.doc.documentElement, attributes)
+
+ def AppendChildren(self, parent, children_specifications):
+ """ Appends multiple children.
+
+ Args:
+ parent: The node to which the children will be added.
+ children_specifications: A list of node specifications.
+ """
+ for specification in children_specifications:
+ # If it's a string, append a text node.
+ # Otherwise append an XML node.
+ if isinstance(specification, str):
+ parent.appendChild(self.doc.createTextNode(specification))
+ else:
+ self.AppendNode(parent, specification)
+
+ def AppendNode(self, parent, specification):
+ """ Appends multiple children.
+
+ Args:
+ parent: The node to which the child will be added.
+ children_specifications: A list, the node specification. The first
+ entry is the name of the element. If the second entry is a
+ dictionary, it is the attributes. The remaining entries of the
+ list are the sub-elements.
+ Returns:
+ The XML element created.
+ """
+ name = specification[0]
+ if not isinstance(name, str):
+ raise Exception('The first item of an EasyXml specification should be '
+ 'a string. Specification was ' + str(specification))
+ element = self.doc.createElement(name)
+ parent.appendChild(element)
+ rest = specification[1:]
+ # The second element is optionally a dictionary of the attributes.
+ if rest and isinstance(rest[0], dict):
+ self.SetAttributes(element, rest[0])
+ rest = rest[1:]
+ if rest:
+ self.AppendChildren(element, rest)
+ return element
+
+ def SetAttributes(self, element, attribute_description):
+ """ Sets the attributes of an element.
+
+ Args:
+ element: The node to which the child will be added.
+ attribute_description: A dictionary that maps attribute names to
+ attribute values.
+ """
+ for attribute, value in attribute_description.iteritems():
+ element.setAttribute(attribute, value)
+
+ def Root(self):
+ """ Returns the root element. """
+ return self.doc.documentElement
+
+ def WriteIfChanged(self, path):
+ """ Writes the XML doc but don't touch the file if unchanged. """
+ f = common.WriteOnDiff(path)
+ fix = xml_fix.XmlFix()
+ self.doc.writexml(f, encoding='utf-8', addindent='', newl='')
+ fix.Cleanup()
+ f.close()
+
+ def __str__(self):
+ """ Converts the doc to a string. """
+ return self.doc.toxml()
diff --git a/Source/ThirdParty/gyp/pylib/gyp/easy_xml_test.py b/Source/ThirdParty/gyp/pylib/gyp/easy_xml_test.py
new file mode 100644
index 000000000..e34821f06
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/easy_xml_test.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+""" Unit tests for the easy_xml.py file. """
+
+import easy_xml
+import unittest
+import StringIO
+
+
+class TestSequenceFunctions(unittest.TestCase):
+
+ def setUp(self):
+ self.stderr = StringIO.StringIO()
+
+ def test_EasyXml_simple(self):
+ xml = easy_xml.EasyXml('test')
+ self.assertEqual(str(xml), '<?xml version="1.0" ?><test/>')
+
+ def test_EasyXml_simple_with_attributes(self):
+ xml = easy_xml.EasyXml('test2', {'a': 'value1', 'b': 'value2'})
+ self.assertEqual(str(xml),
+ '<?xml version="1.0" ?><test2 a="value1" b="value2"/>')
+
+ def test_EasyXml_add_node(self):
+ # We want to create:
+ target = ('<?xml version="1.0" ?>'
+ '<test3>'
+ '<GrandParent>'
+ '<Parent1>'
+ '<Child/>'
+ '</Parent1>'
+ '<Parent2/>'
+ '</GrandParent>'
+ '</test3>')
+
+ # Do it the hard way first:
+ xml = easy_xml.EasyXml('test3')
+ grand_parent = xml.AppendNode(xml.Root(), ['GrandParent'])
+ parent1 = xml.AppendNode(grand_parent, ['Parent1'])
+ parent2 = xml.AppendNode(grand_parent, ['Parent2'])
+ xml.AppendNode(parent1, ['Child'])
+ self.assertEqual(str(xml), target)
+
+ # Do it the easier way:
+ xml = easy_xml.EasyXml('test3')
+ xml.AppendNode(xml.Root(),
+ ['GrandParent',
+ ['Parent1', ['Child']],
+ ['Parent2']])
+ self.assertEqual(str(xml), target)
+
+ def test_EasyXml_complex(self):
+ # We want to create:
+ target = ('<?xml version="1.0" ?>'
+ '<Project>'
+ '<PropertyGroup Label="Globals">'
+ '<ProjectGuid>{D2250C20-3A94-4FB9-AF73-11BC5B73884B}</ProjectGuid>'
+ '<Keyword>Win32Proj</Keyword>'
+ '<RootNamespace>automated_ui_tests</RootNamespace>'
+ '</PropertyGroup>'
+ '<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props"/>'
+ '<PropertyGroup Condition="\'$(Configuration)|$(Platform)\'==\''
+ 'Debug|Win32\'" Label="Configuration">'
+ '<ConfigurationType>Application</ConfigurationType>'
+ '<CharacterSet>Unicode</CharacterSet>'
+ '</PropertyGroup>'
+ '</Project>')
+
+ xml = easy_xml.EasyXml('Project')
+ xml.AppendChildren(xml.Root(), [
+ ['PropertyGroup', {'Label': 'Globals'},
+ ['ProjectGuid', '{D2250C20-3A94-4FB9-AF73-11BC5B73884B}'],
+ ['Keyword', 'Win32Proj'],
+ ['RootNamespace', 'automated_ui_tests']
+ ],
+ ['Import', {'Project': '$(VCTargetsPath)\\Microsoft.Cpp.props'}],
+ ['PropertyGroup',
+ {'Condition': "'$(Configuration)|$(Platform)'=='Debug|Win32'",
+ 'Label': 'Configuration'},
+ ['ConfigurationType', 'Application'],
+ ['CharacterSet', 'Unicode']
+ ]
+ ])
+ self.assertEqual(str(xml), target)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Source/ThirdParty/gyp/pylib/gyp/generator/__init__.py b/Source/ThirdParty/gyp/pylib/gyp/generator/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/generator/__init__.py
diff --git a/Source/ThirdParty/gyp/pylib/gyp/generator/filelist.py b/Source/ThirdParty/gyp/pylib/gyp/generator/filelist.py
new file mode 100644
index 000000000..9e39363f9
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/generator/filelist.py
@@ -0,0 +1,45 @@
+#!/usr/bin/python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""filelist output module
+
+Just dumps the list of files to a text file for import into another build system.
+"""
+
+import gyp.common
+import errno
+import os
+
+
+# FIXME: These defaults are wrong, but serve to allow us to generate something for now.
+generator_default_variables = {
+ 'OS': 'linux',
+ 'PRODUCT_DIR': '$(builddir)',
+}
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ options = params['options']
+
+ for build_file, build_file_dict in data.iteritems():
+ (build_file_root, build_file_ext) = os.path.splitext(build_file)
+ if build_file_ext != '.gyp':
+ continue
+
+ filelist_suffix = ".am" # FIXME: This should be configurable in the .gyp file
+ filelist_path = build_file_root + options.suffix + filelist_suffix
+
+ with open(filelist_path, 'w') as output:
+
+ for qualified_target in target_list:
+ [input_file, target] = gyp.common.ParseQualifiedTarget(qualified_target)[0:2]
+
+ lowered_target = target.lower() # FIXME: This is a hack for now to matche gtk automake style.
+
+ output.write("%s_sources += \\\n" % lowered_target)
+
+ for source in target_dicts[qualified_target]['sources']:
+ output.write("\t%s \\\n" % source)
diff --git a/Source/ThirdParty/gyp/pylib/gyp/generator/gypd.py b/Source/ThirdParty/gyp/pylib/gyp/generator/gypd.py
new file mode 100644
index 000000000..948f0b852
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/generator/gypd.py
@@ -0,0 +1,88 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""gypd output module
+
+This module produces gyp input as its output. Output files are given the
+.gypd extension to avoid overwriting the .gyp files that they are generated
+from. Internal references to .gyp files (such as those found in
+"dependencies" sections) are not adjusted to point to .gypd files instead;
+unlike other paths, which are relative to the .gyp or .gypd file, such paths
+are relative to the directory from which gyp was run to create the .gypd file.
+
+This generator module is intended to be a sample and a debugging aid, hence
+the "d" for "debug" in .gypd. It is useful to inspect the results of the
+various merges, expansions, and conditional evaluations performed by gyp
+and to see a representation of what would be fed to a generator module.
+
+It's not advisable to rename .gypd files produced by this module to .gyp,
+because they will have all merges, expansions, and evaluations already
+performed and the relevant constructs not present in the output; paths to
+dependencies may be wrong; and various sections that do not belong in .gyp
+files such as such as "included_files" and "*_excluded" will be present.
+Output will also be stripped of comments. This is not intended to be a
+general-purpose gyp pretty-printer; for that, you probably just want to
+run "pprint.pprint(eval(open('source.gyp').read()))", which will still strip
+comments but won't do all of the other things done to this module's output.
+
+The specific formatting of the output generated by this module is subject
+to change.
+"""
+
+
+import gyp.common
+import errno
+import os
+import pprint
+
+
+# These variables should just be spit back out as variable references.
+_generator_identity_variables = [
+ 'EXECUTABLE_PREFIX',
+ 'EXECUTABLE_SUFFIX',
+ 'INTERMEDIATE_DIR',
+ 'PRODUCT_DIR',
+ 'RULE_INPUT_ROOT',
+ 'RULE_INPUT_EXT',
+ 'RULE_INPUT_NAME',
+ 'RULE_INPUT_PATH',
+ 'SHARED_INTERMEDIATE_DIR',
+]
+
+# gypd doesn't define a default value for OS like many other generator
+# modules. Specify "-D OS=whatever" on the command line to provide a value.
+generator_default_variables = {
+}
+
+# gypd supports multiple toolsets
+generator_supports_multiple_toolsets = True
+
+# TODO(mark): This always uses <, which isn't right. The input module should
+# notify the generator to tell it which phase it is operating in, and this
+# module should use < for the early phase and then switch to > for the late
+# phase. Bonus points for carrying @ back into the output too.
+for v in _generator_identity_variables:
+ generator_default_variables[v] = '<(%s)' % v
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ output_files = {}
+ for qualified_target in target_list:
+ [input_file, target] = \
+ gyp.common.ParseQualifiedTarget(qualified_target)[0:2]
+
+ if input_file[-4:] != '.gyp':
+ continue
+ input_file_stem = input_file[:-4]
+ output_file = input_file_stem + params['options'].suffix + '.gypd'
+
+ if not output_file in output_files:
+ output_files[output_file] = input_file
+
+ for output_file, input_file in output_files.iteritems():
+ output = open(output_file, 'w')
+ pprint.pprint(data[input_file], output)
+ output.close()
diff --git a/Source/ThirdParty/gyp/pylib/gyp/generator/gypsh.py b/Source/ThirdParty/gyp/pylib/gyp/generator/gypsh.py
new file mode 100644
index 000000000..f48b03fa7
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/generator/gypsh.py
@@ -0,0 +1,57 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""gypsh output module
+
+gypsh is a GYP shell. It's not really a generator per se. All it does is
+fire up an interactive Python session with a few local variables set to the
+variables passed to the generator. Like gypd, it's intended as a debugging
+aid, to facilitate the exploration of .gyp structures after being processed
+by the input module.
+
+The expected usage is "gyp -f gypsh -D OS=desired_os".
+"""
+
+
+import code
+import sys
+
+
+# All of this stuff about generator variables was lovingly ripped from gypd.py.
+# That module has a much better description of what's going on and why.
+_generator_identity_variables = [
+ 'EXECUTABLE_PREFIX',
+ 'EXECUTABLE_SUFFIX',
+ 'INTERMEDIATE_DIR',
+ 'PRODUCT_DIR',
+ 'RULE_INPUT_ROOT',
+ 'RULE_INPUT_EXT',
+ 'RULE_INPUT_NAME',
+ 'RULE_INPUT_PATH',
+ 'SHARED_INTERMEDIATE_DIR',
+]
+
+generator_default_variables = {
+}
+
+for v in _generator_identity_variables:
+ generator_default_variables[v] = '<(%s)' % v
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ locals = {
+ 'target_list': target_list,
+ 'target_dicts': target_dicts,
+ 'data': data,
+ }
+
+ # Use a banner that looks like the stock Python one and like what
+ # code.interact uses by default, but tack on something to indicate what
+ # locals are available, and identify gypsh.
+ banner='Python %s on %s\nlocals.keys() = %s\ngypsh' % \
+ (sys.version, sys.platform, repr(sorted(locals.keys())))
+
+ code.interact(banner, local=locals)
diff --git a/Source/ThirdParty/gyp/pylib/gyp/generator/make.py b/Source/ThirdParty/gyp/pylib/gyp/generator/make.py
new file mode 100644
index 000000000..e72c0fbfa
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/generator/make.py
@@ -0,0 +1,1423 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Notes:
+#
+# This is all roughly based on the Makefile system used by the Linux
+# kernel, but is a non-recursive make -- we put the entire dependency
+# graph in front of make and let it figure it out.
+#
+# The code below generates a separate .mk file for each target, but
+# all are sourced by the top-level Makefile. This means that all
+# variables in .mk-files clobber one another. Be careful to use :=
+# where appropriate for immediate evaluation, and similarly to watch
+# that you're not relying on a variable value to last beween different
+# .mk files.
+#
+# TODOs:
+#
+# Global settings and utility functions are currently stuffed in the
+# toplevel Makefile. It may make sense to generate some .mk files on
+# the side to keep the the files readable.
+
+import gyp
+import gyp.common
+import gyp.system_test
+import os.path
+import os
+
+# Debugging-related imports -- remove me once we're solid.
+import code
+import pprint
+
+generator_default_variables = {
+ 'EXECUTABLE_PREFIX': '',
+ 'EXECUTABLE_SUFFIX': '',
+ 'OS': 'linux',
+ 'STATIC_LIB_PREFIX': 'lib',
+ 'SHARED_LIB_PREFIX': 'lib',
+ 'STATIC_LIB_SUFFIX': '.a',
+ 'SHARED_LIB_SUFFIX': '.so',
+ 'INTERMEDIATE_DIR': '$(obj).$(TOOLSET)/geni',
+ 'SHARED_INTERMEDIATE_DIR': '$(obj)/gen',
+ 'PRODUCT_DIR': '$(builddir)',
+ 'SHARED_LIB_DIR': '$(builddir)/lib.$(TOOLSET)',
+ 'LIB_DIR': '$(obj).$(TOOLSET)',
+ 'RULE_INPUT_ROOT': '%(INPUT_ROOT)s', # This gets expanded by Python.
+ 'RULE_INPUT_PATH': '$(abspath $<)',
+ 'RULE_INPUT_EXT': '$(suffix $<)',
+ 'RULE_INPUT_NAME': '$(notdir $<)',
+
+ # This appears unused --- ?
+ 'CONFIGURATION_NAME': '$(BUILDTYPE)',
+}
+
+# Make supports multiple toolsets
+generator_supports_multiple_toolsets = True
+
+def ensure_directory_exists(path):
+ dir = os.path.dirname(path)
+ if dir and not os.path.exists(dir):
+ os.makedirs(dir)
+
+# Header of toplevel Makefile.
+# This should go into the build tree, but it's easier to keep it here for now.
+SHARED_HEADER = ("""\
+# We borrow heavily from the kernel build setup, though we are simpler since
+# we don't have Kconfig tweaking settings on us.
+
+# The implicit make rules have it looking for RCS files, among other things.
+# We instead explicitly write all the rules we care about.
+# It's even quicker (saves ~200ms) to pass -r on the command line.
+MAKEFLAGS=-r
+
+# The source directory tree.
+srcdir := %(srcdir)s
+
+# The name of the builddir.
+builddir_name ?= %(builddir)s
+
+# The V=1 flag on command line makes us verbosely print command lines.
+ifdef V
+ quiet=
+else
+ quiet=quiet_
+endif
+
+# Specify BUILDTYPE=Release on the command line for a release build.
+BUILDTYPE ?= %(default_configuration)s
+
+# Directory all our build output goes into.
+# Note that this must be two directories beneath src/ for unit tests to pass,
+# as they reach into the src/ directory for data with relative paths.
+builddir ?= $(builddir_name)/$(BUILDTYPE)
+abs_builddir := $(abspath $(builddir))
+depsdir := $(builddir)/.deps
+
+# Object output directory.
+obj := $(builddir)/obj
+abs_obj := $(abspath $(obj))
+
+# We build up a list of every single one of the targets so we can slurp in the
+# generated dependency rule Makefiles in one pass.
+all_deps :=
+
+# C++ apps need to be linked with g++. Not sure what's appropriate.
+#
+# Note, the flock is used to seralize linking. Linking is a memory-intensive
+# process so running parallel links can often lead to thrashing. To disable
+# the serialization, override LINK via an envrionment variable as follows:
+#
+# export LINK="$(CXX)"
+#
+# This will allow make to invoke N linker processes as specified in -jN.
+LINK ?= flock $(builddir)/linker.lock $(CXX) %(LINK_flags)s
+
+CC.target ?= $(CC)
+CFLAGS.target ?= $(CFLAGS)
+CXX.target ?= $(CXX)
+CXXFLAGS.target ?= $(CXXFLAGS)
+LINK.target ?= $(LINK)
+LDFLAGS.target ?= $(LDFLAGS)
+AR.target ?= $(AR)
+ARFLAGS.target ?= %(ARFLAGS.target)s
+
+# N.B.: the logic of which commands to run should match the computation done
+# in gyp's make.py where ARFLAGS.host etc. is computed.
+# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
+# to replicate this environment fallback in make as well.
+CC.host ?= gcc
+CFLAGS.host ?=
+CXX.host ?= g++
+CXXFLAGS.host ?=
+LINK.host ?= g++
+LDFLAGS.host ?=
+AR.host ?= ar
+ARFLAGS.host := %(ARFLAGS.host)s
+
+# Flags to make gcc output dependency info. Note that you need to be
+# careful here to use the flags that ccache and distcc can understand.
+# We write to a dep file on the side first and then rename at the end
+# so we can't end up with a broken dep file.
+depfile = $(depsdir)/$@.d
+DEPFLAGS = -MMD -MF $(depfile).raw
+
+# We have to fixup the deps output in a few ways.
+# (1) the file output should mention the proper .o file.
+# ccache or distcc lose the path to the target, so we convert a rule of
+# the form:
+# foobar.o: DEP1 DEP2
+# into
+# path/to/foobar.o: DEP1 DEP2
+# (2) we want missing files not to cause us to fail to build.
+# We want to rewrite
+# foobar.o: DEP1 DEP2 \\
+# DEP3
+# to
+# DEP1:
+# DEP2:
+# DEP3:
+# so if the files are missing, they're just considered phony rules.
+# We have to do some pretty insane escaping to get those backslashes
+# and dollar signs past make, the shell, and sed at the same time."""
+r"""
+define fixup_dep
+# The depfile may not exist if the input file didn't have any #includes.
+touch $(depfile).raw
+# Fixup path as in (1).
+sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
+# Add extra rules as in (2).
+# We remove slashes and replace spaces with new lines;
+# remove blank lines;
+# delete the first line and append a colon to the remaining lines.
+sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
+ grep -v '^$$' |\
+ sed -e 1d -e 's|$$|:|' \
+ >> $(depfile)
+rm $(depfile).raw
+endef
+"""
+"""
+# Command definitions:
+# - cmd_foo is the actual command to run;
+# - quiet_cmd_foo is the brief-output summary of the command.
+
+quiet_cmd_cc = CC($(TOOLSET)) $@
+cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_cxx = CXX($(TOOLSET)) $@
+cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) $(ARFLAGS.$(TOOLSET)) $@ $(filter %%.o,$^)
+
+quiet_cmd_touch = TOUCH $@
+cmd_touch = touch $@
+
+quiet_cmd_copy = COPY $@
+# send stderr to /dev/null to ignore messages when linking directories.
+cmd_copy = ln -f $< $@ 2>/dev/null || cp -af $< $@
+
+# Due to circular dependencies between libraries :(, we wrap the
+# special "figure out circular dependencies" flags around the entire
+# input list during linking.
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
+
+# Shared-object link (for generating .so).
+# Set SONAME to the library filename so our binaries don't reference the local,
+# absolute paths used on the link command-line.
+# TODO: perhaps this can share with the LINK command above?
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
+"""
+r"""
+# Define an escape_quotes function to escape single quotes.
+# This allows us to handle quotes properly as long as we always use
+# use single quotes and escape_quotes.
+escape_quotes = $(subst ','\'',$(1))
+# This comment is here just to include a ' to unconfuse syntax highlighting.
+# Define an escape_vars function to escape '$' variable syntax.
+# This allows us to read/write command lines with shell variables (e.g.
+# $LD_LIBRARY_PATH), without triggering make substitution.
+escape_vars = $(subst $$,$$$$,$(1))
+# Helper that expands to a shell command to echo a string exactly as it is in
+# make. This uses printf instead of echo because printf's behaviour with respect
+# to escape sequences is more portable than echo's across different shells
+# (e.g., dash, bash).
+exact_echo = printf '%%s\n' '$(call escape_quotes,$(1))'
+"""
+"""
+# Helper to compare the command we're about to run against the command
+# we logged the last time we ran the command. Produces an empty
+# string (false) when the commands match.
+# Tricky point: Make has no string-equality test function.
+# The kernel uses the following, but it seems like it would have false
+# positives, where one string reordered its arguments.
+# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \\
+# $(filter-out $(cmd_$@), $(cmd_$(1))))
+# We instead substitute each for the empty string into the other, and
+# say they're equal if both substitutions produce the empty string.
+command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$@)),\\
+ $(subst $(cmd_$@),,$(cmd_$(1))))
+
+# Helper that is non-empty when a prerequisite changes.
+# Normally make does this implicitly, but we force rules to always run
+# so we can check their command lines.
+# $? -- new prerequisites
+# $| -- order-only dependencies
+prereq_changed = $(filter-out $|,$?)
+
+# do_cmd: run a command via the above cmd_foo names, if necessary.
+# Should always run for a given target to handle command-line changes.
+# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
+define do_cmd
+$(if $(or $(command_changed),$(prereq_changed)),
+ @$(call exact_echo, $($(quiet)cmd_$(1)))
+ @mkdir -p $(dir $@) $(dir $(depfile))
+ @$(cmd_$(1))
+ @$(call exact_echo,$(call escape_vars,cmd_$@ := $(cmd_$(1)))) > $(depfile)
+ @$(if $(2),$(fixup_dep))
+)
+endef
+
+# Declare "all" target first so it is the default, even though we don't have the
+# deps yet.
+.PHONY: all
+all:
+
+# Use FORCE_DO_CMD to force a target to run. Should be coupled with
+# do_cmd.
+.PHONY: FORCE_DO_CMD
+FORCE_DO_CMD:
+
+""")
+
+ROOT_HEADER_SUFFIX_RULES = ("""\
+# Suffix rules, putting all outputs into $(obj).
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# Try building from generated source, too.
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+""")
+
+SHARED_HEADER_SUFFIX_RULES_COMMENT1 = ("""\
+# Suffix rules, putting all outputs into $(obj).
+""")
+
+SHARED_HEADER_SUFFIX_RULES_SRCDIR = {
+ '.c': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+"""),
+ '.s': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+"""),
+ '.S': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+"""),
+ '.cpp': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+"""),
+ '.cc': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+"""),
+ '.cxx': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+"""),
+}
+
+SHARED_HEADER_SUFFIX_RULES_COMMENT2 = ("""\
+# Try building from generated source, too.
+""")
+
+SHARED_HEADER_SUFFIX_RULES_OBJDIR1 = {
+ '.c': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+"""),
+ '.cc': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+"""),
+ '.cpp': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+"""),
+}
+
+SHARED_HEADER_SUFFIX_RULES_OBJDIR2 = {
+ '.c': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+"""),
+ '.cc': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+"""),
+ '.cpp': ("""\
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+"""),
+}
+
+SHARED_HEADER_SUFFIX_RULES = (
+ SHARED_HEADER_SUFFIX_RULES_COMMENT1 +
+ ''.join(SHARED_HEADER_SUFFIX_RULES_SRCDIR.values()) +
+ SHARED_HEADER_SUFFIX_RULES_COMMENT2 +
+ ''.join(SHARED_HEADER_SUFFIX_RULES_OBJDIR1.values()) +
+ ''.join(SHARED_HEADER_SUFFIX_RULES_OBJDIR2.values())
+)
+
+SHARED_FOOTER = """\
+# "all" is a concatenation of the "all" targets from all the included
+# sub-makefiles. This is just here to clarify.
+all:
+
+# Add in dependency-tracking rules. $(all_deps) is the list of every single
+# target in our tree. First, only consider targets that already have been
+# built, as unbuilt targets will be built regardless of dependency info:
+all_deps := $(wildcard $(sort $(all_deps)))
+# Of those, only consider the ones with .d (dependency) info:
+d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
+ifneq ($(d_files),)
+ # Rather than include each individual .d file, concatenate them into a
+ # single file which make is able to load faster. We split this into
+ # commands that take 1000 files at a time to avoid overflowing the
+ # command line.
+ $(shell cat $(wordlist 1,1000,$(d_files)) > $(depsdir)/all.deps)
+%(generate_all_deps)s
+ # make looks for ways to re-generate included makefiles, but in our case, we
+ # don't have a direct way. Explicitly telling make that it has nothing to do
+ # for them makes it go faster.
+ $(depsdir)/all.deps: ;
+
+ include $(depsdir)/all.deps
+endif
+"""
+
+header = """\
+# This file is generated by gyp; do not edit.
+
+"""
+
+
+def Compilable(filename):
+ """Return true if the file is compilable (should be in OBJS)."""
+ for res in (filename.endswith(e) for e
+ in ['.c', '.cc', '.cpp', '.cxx', '.s', '.S']):
+ if res:
+ return True
+ return False
+
+
+def Linkable(filename):
+ """Return true if the file is linkable (should be on the link line)."""
+ return filename.endswith('.o')
+
+
+def Target(filename):
+ """Translate a compilable filename to its .o target."""
+ return os.path.splitext(filename)[0] + '.o'
+
+
+def EscapeShellArgument(s):
+ """Quotes an argument so that it will be interpreted literally by a POSIX
+ shell. Taken from
+ http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python
+ """
+ return "'" + s.replace("'", "'\\''") + "'"
+
+
+def EscapeMakeVariableExpansion(s):
+ """Make has its own variable expansion syntax using $. We must escape it for
+ string to be interpreted literally."""
+ return s.replace('$', '$$')
+
+
+def EscapeCppDefine(s):
+ """Escapes a CPP define so that it will reach the compiler unaltered."""
+ s = EscapeShellArgument(s)
+ s = EscapeMakeVariableExpansion(s)
+ return s
+
+
+def QuoteIfNecessary(string):
+ """TODO: Should this ideally be replaced with one or more of the above
+ functions?"""
+ if '"' in string:
+ string = '"' + string.replace('"', '\\"') + '"'
+ return string
+
+
+def StringToMakefileVariable(string):
+ """Convert a string to a value that is acceptable as a make variable name."""
+ # TODO: replace other metacharacters that we encounter.
+ return string.replace(' ', '_')
+
+
+srcdir_prefix = ''
+def Sourceify(path):
+ """Convert a path to its source directory form."""
+ if '$(' in path:
+ return path
+ if os.path.isabs(path):
+ return path
+ return srcdir_prefix + path
+
+
+# Map from qualified target to path to output.
+target_outputs = {}
+# Map from qualified target to a list of all linker dependencies,
+# transitively expanded.
+# Used in building shared-library-based executables.
+target_link_deps = {}
+
+
+class MakefileWriter:
+ """MakefileWriter packages up the writing of one target-specific foobar.mk.
+
+ Its only real entry point is Write(), and is mostly used for namespacing.
+ """
+
+ def __init__(self):
+ # Keep track of the total number of outputs for this makefile.
+ self._num_outputs = 0
+
+
+ def NumOutputs(self):
+ return self._num_outputs
+
+
+ def Write(self, qualified_target, base_path, output_filename, spec, configs,
+ part_of_all):
+ """The main entry point: writes a .mk file for a single target.
+
+ Arguments:
+ qualified_target: target we're generating
+ base_path: path relative to source root we're building in, used to resolve
+ target-relative paths
+ output_filename: output .mk file name to write
+ spec, configs: gyp info
+ part_of_all: flag indicating this target is part of 'all'
+ """
+ ensure_directory_exists(output_filename)
+
+ self.fp = open(output_filename, 'w')
+
+ self.fp.write(header)
+
+ self.path = base_path
+ self.target = spec['target_name']
+ self.type = spec['type']
+ self.toolset = spec['toolset']
+
+ deps, link_deps = self.ComputeDeps(spec)
+
+ # Some of the generation below can add extra output, sources, or
+ # link dependencies. All of the out params of the functions that
+ # follow use names like extra_foo.
+ extra_outputs = []
+ extra_sources = []
+ extra_link_deps = []
+
+ self.output = self.ComputeOutput(spec)
+ self._INSTALLABLE_TARGETS = ('executable', 'loadable_module',
+ 'shared_library')
+ if self.type in self._INSTALLABLE_TARGETS:
+ self.alias = os.path.basename(self.output)
+ install_path = self._InstallableTargetInstallPath()
+ else:
+ self.alias = self.output
+ install_path = self.output
+
+ self.WriteLn("TOOLSET := " + self.toolset)
+ self.WriteLn("TARGET := " + self.target)
+
+ # Actions must come first, since they can generate more OBJs for use below.
+ if 'actions' in spec:
+ self.WriteActions(spec['actions'], extra_sources, extra_outputs,
+ part_of_all)
+
+ # Rules must be early like actions.
+ if 'rules' in spec:
+ self.WriteRules(spec['rules'], extra_sources, extra_outputs, part_of_all)
+
+ if 'copies' in spec:
+ self.WriteCopies(spec['copies'], extra_outputs, part_of_all)
+
+ all_sources = spec.get('sources', []) + extra_sources
+ if all_sources:
+ self.WriteSources(configs, deps, all_sources,
+ extra_outputs, extra_link_deps, part_of_all)
+ sources = filter(Compilable, all_sources)
+ if sources:
+ self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1)
+ extensions = set([os.path.splitext(s)[1] for s in sources])
+ for ext in extensions:
+ if ext in SHARED_HEADER_SUFFIX_RULES_SRCDIR:
+ self.WriteLn(SHARED_HEADER_SUFFIX_RULES_SRCDIR[ext])
+ self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT2)
+ for ext in extensions:
+ if ext in SHARED_HEADER_SUFFIX_RULES_OBJDIR1:
+ self.WriteLn(SHARED_HEADER_SUFFIX_RULES_OBJDIR1[ext])
+ for ext in extensions:
+ if ext in SHARED_HEADER_SUFFIX_RULES_OBJDIR2:
+ self.WriteLn(SHARED_HEADER_SUFFIX_RULES_OBJDIR2[ext])
+ self.WriteLn('# End of this set of suffix rules')
+
+
+ self.WriteTarget(spec, configs, deps,
+ extra_link_deps + link_deps, extra_outputs, part_of_all)
+
+ # Update global list of target outputs, used in dependency tracking.
+ target_outputs[qualified_target] = install_path
+
+ # Update global list of link dependencies.
+ if self.type == 'static_library':
+ target_link_deps[qualified_target] = [self.output]
+ elif self.type == 'shared_library':
+ # Anyone that uses us transitively depend on all of our link
+ # dependencies.
+ target_link_deps[qualified_target] = [self.output] + link_deps
+
+ self.fp.close()
+
+
+ def WriteSubMake(self, output_filename, makefile_path, targets, build_dir):
+ """Write a "sub-project" Makefile.
+
+ This is a small, wrapper Makefile that calls the top-level Makefile to build
+ the targets from a single gyp file (i.e. a sub-project).
+
+ Arguments:
+ output_filename: sub-project Makefile name to write
+ makefile_path: path to the top-level Makefile
+ targets: list of "all" targets for this sub-project
+ build_dir: build output directory, relative to the sub-project
+ """
+ ensure_directory_exists(output_filename)
+ self.fp = open(output_filename, 'w')
+ self.fp.write(header)
+ # For consistency with other builders, put sub-project build output in the
+ # sub-project dir (see test/subdirectory/gyptest-subdir-all.py).
+ self.WriteLn('export builddir_name ?= %s' %
+ os.path.join(os.path.dirname(output_filename), build_dir))
+ self.WriteLn('.PHONY: all')
+ self.WriteLn('all:')
+ if makefile_path:
+ makefile_path = ' -C ' + makefile_path
+ self.WriteLn('\t$(MAKE)%s %s' % (makefile_path, ' '.join(targets)))
+ self.fp.close()
+
+
+ def WriteActions(self, actions, extra_sources, extra_outputs, part_of_all):
+ """Write Makefile code for any 'actions' from the gyp input.
+
+ extra_sources: a list that will be filled in with newly generated source
+ files, if any
+ extra_outputs: a list that will be filled in with any outputs of these
+ actions (used to make other pieces dependent on these
+ actions)
+ part_of_all: flag indicating this target is part of 'all'
+ """
+ for action in actions:
+ name = self.target + '_' + StringToMakefileVariable(action['action_name'])
+ self.WriteLn('### Rules for action "%s":' % action['action_name'])
+ inputs = action['inputs']
+ outputs = action['outputs']
+
+ # Build up a list of outputs.
+ # Collect the output dirs we'll need.
+ dirs = set()
+ for out in outputs:
+ dir = os.path.split(out)[0]
+ if dir:
+ dirs.add(dir)
+ if int(action.get('process_outputs_as_sources', False)):
+ extra_sources += outputs
+
+ # Write the actual command.
+ command = gyp.common.EncodePOSIXShellList(action['action'])
+ if 'message' in action:
+ self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, action['message']))
+ else:
+ self.WriteLn('quiet_cmd_%s = ACTION %s $@' % (name, name))
+ if len(dirs) > 0:
+ command = 'mkdir -p %s' % ' '.join(dirs) + '; ' + command
+ # Set LD_LIBRARY_PATH in case the action runs an executable from this
+ # build which links to shared libs from this build.
+ if self.path:
+ cd_action = 'cd %s; ' % Sourceify(self.path)
+ else:
+ cd_action = ''
+ # actions run on the host, so they should in theory only use host
+ # libraries, but until everything is made cross-compile safe, also use
+ # target libraries.
+ # TODO(piman): when everything is cross-compile safe, remove lib.target
+ self.WriteLn('cmd_%s = export LD_LIBRARY_PATH=$(builddir)/lib.host:'
+ '$(builddir)/lib.target:$$LD_LIBRARY_PATH; %s%s'
+ % (name, cd_action, command))
+ self.WriteLn()
+ outputs = map(self.Absolutify, outputs)
+ # The makefile rules are all relative to the top dir, but the gyp actions
+ # are defined relative to their containing dir. This replaces the obj
+ # variable for the action rule with an absolute version so that the output
+ # goes in the right place.
+ # Only write the 'obj' and 'builddir' rules for the "primary" output (:1);
+ # it's superfluous for the "extra outputs", and this avoids accidentally
+ # writing duplicate dummy rules for those outputs.
+ self.WriteMakeRule(outputs[:1], ['obj := $(abs_obj)'])
+ self.WriteMakeRule(outputs[:1], ['builddir := $(abs_builddir)'])
+ self.WriteDoCmd(outputs, map(Sourceify, map(self.Absolutify, inputs)),
+ part_of_all=part_of_all, command=name)
+
+ # Stuff the outputs in a variable so we can refer to them later.
+ outputs_variable = 'action_%s_outputs' % name
+ self.WriteLn('%s := %s' % (outputs_variable, ' '.join(outputs)))
+ extra_outputs.append('$(%s)' % outputs_variable)
+ self.WriteLn()
+
+ self.WriteLn()
+
+
+ def WriteRules(self, rules, extra_sources, extra_outputs, part_of_all):
+ """Write Makefile code for any 'rules' from the gyp input.
+
+ extra_sources: a list that will be filled in with newly generated source
+ files, if any
+ extra_outputs: a list that will be filled in with any outputs of these
+ rules (used to make other pieces dependent on these rules)
+ part_of_all: flag indicating this target is part of 'all'
+ """
+ for rule in rules:
+ name = self.target + '_' + StringToMakefileVariable(rule['rule_name'])
+ count = 0
+ self.WriteLn('### Generated for rule %s:' % name)
+
+ all_outputs = []
+
+ for rule_source in rule.get('rule_sources', []):
+ dirs = set()
+ rule_source_basename = os.path.basename(rule_source)
+ (rule_source_root, rule_source_ext) = \
+ os.path.splitext(rule_source_basename)
+
+ outputs = [self.ExpandInputRoot(out, rule_source_root)
+ for out in rule['outputs']]
+ for out in outputs:
+ dir = os.path.dirname(out)
+ if dir:
+ dirs.add(dir)
+ if int(rule.get('process_outputs_as_sources', False)):
+ extra_sources.append(out)
+ all_outputs += outputs
+ inputs = map(Sourceify, map(self.Absolutify, [rule_source] +
+ rule.get('inputs', [])))
+ actions = ['$(call do_cmd,%s_%d)' % (name, count)]
+
+ if name == 'resources_grit':
+ # HACK: This is ugly. Grit intentionally doesn't touch the
+ # timestamp of its output file when the file doesn't change,
+ # which is fine in hash-based dependency systems like scons
+ # and forge, but not kosher in the make world. After some
+ # discussion, hacking around it here seems like the least
+ # amount of pain.
+ actions += ['@touch --no-create $@']
+
+ # Only write the 'obj' and 'builddir' rules for the "primary" output
+ # (:1); it's superfluous for the "extra outputs", and this avoids
+ # accidentally writing duplicate dummy rules for those outputs.
+ self.WriteMakeRule(outputs[:1], ['obj := $(abs_obj)'])
+ self.WriteMakeRule(outputs[:1], ['builddir := $(abs_builddir)'])
+ self.WriteMakeRule(outputs, inputs + ['FORCE_DO_CMD'], actions)
+ self.WriteLn('all_deps += %s' % ' '.join(outputs))
+ self._num_outputs += len(outputs)
+
+ action = [self.ExpandInputRoot(ac, rule_source_root)
+ for ac in rule['action']]
+ mkdirs = ''
+ if len(dirs) > 0:
+ mkdirs = 'mkdir -p %s; ' % ' '.join(dirs)
+ if self.path:
+ cd_action = 'cd %s; ' % Sourceify(self.path)
+ else:
+ cd_action = ''
+ # Set LD_LIBRARY_PATH in case the rule runs an executable from this
+ # build which links to shared libs from this build.
+ # rules run on the host, so they should in theory only use host
+ # libraries, but until everything is made cross-compile safe, also use
+ # target libraries.
+ # TODO(piman): when everything is cross-compile safe, remove lib.target
+ self.WriteLn(
+ "cmd_%(name)s_%(count)d = export LD_LIBRARY_PATH="
+ "$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; "
+ "%(cd_action)s%(mkdirs)s%(action)s" % {
+ 'action': gyp.common.EncodePOSIXShellList(action),
+ 'cd_action': cd_action,
+ 'count': count,
+ 'mkdirs': mkdirs,
+ 'name': name,
+ })
+ self.WriteLn(
+ 'quiet_cmd_%(name)s_%(count)d = RULE %(name)s_%(count)d $@' % {
+ 'count': count,
+ 'name': name,
+ })
+ self.WriteLn()
+ count += 1
+
+ outputs_variable = 'rule_%s_outputs' % name
+ self.WriteList(all_outputs, outputs_variable)
+ extra_outputs.append('$(%s)' % outputs_variable)
+
+ self.WriteLn('### Finished generating for rule: %s' % name)
+ self.WriteLn()
+ self.WriteLn('### Finished generating for all rules')
+ self.WriteLn('')
+
+
+ def WriteCopies(self, copies, extra_outputs, part_of_all):
+ """Write Makefile code for any 'copies' from the gyp input.
+
+ extra_outputs: a list that will be filled in with any outputs of this action
+ (used to make other pieces dependent on this action)
+ part_of_all: flag indicating this target is part of 'all'
+ """
+ self.WriteLn('### Generated for copy rule.')
+
+ variable = self.target + '_copies'
+ outputs = []
+ for copy in copies:
+ for path in copy['files']:
+ path = Sourceify(self.Absolutify(path))
+ filename = os.path.split(path)[1]
+ output = Sourceify(self.Absolutify(os.path.join(copy['destination'],
+ filename)))
+ self.WriteDoCmd([output], [path], 'copy', part_of_all)
+ outputs.append(output)
+ self.WriteLn('%s = %s' % (variable, ' '.join(outputs)))
+ extra_outputs.append('$(%s)' % variable)
+ self.WriteLn()
+
+
+ def WriteSources(self, configs, deps, sources,
+ extra_outputs, extra_link_deps,
+ part_of_all):
+ """Write Makefile code for any 'sources' from the gyp input.
+ These are source files necessary to build the current target.
+
+ configs, deps, sources: input from gyp.
+ extra_outputs: a list of extra outputs this action should be dependent on;
+ used to serialize action/rules before compilation
+ extra_link_deps: a list that will be filled in with any outputs of
+ compilation (to be used in link lines)
+ part_of_all: flag indicating this target is part of 'all'
+ """
+
+ # Write configuration-specific variables for CFLAGS, etc.
+ for configname in sorted(configs.keys()):
+ config = configs[configname]
+ self.WriteList(config.get('defines'), 'DEFS_%s' % configname, prefix='-D',
+ quoter=EscapeCppDefine)
+ self.WriteLn("# Flags passed to both C and C++ files.");
+ self.WriteList(config.get('cflags'), 'CFLAGS_%s' % configname)
+ self.WriteLn("# Flags passed to only C (and not C++) files.");
+ self.WriteList(config.get('cflags_c'), 'CFLAGS_C_%s' % configname)
+ self.WriteLn("# Flags passed to only C++ (and not C) files.");
+ self.WriteList(config.get('cflags_cc'), 'CFLAGS_CC_%s' % configname)
+ includes = config.get('include_dirs')
+ if includes:
+ includes = map(Sourceify, map(self.Absolutify, includes))
+ self.WriteList(includes, 'INCS_%s' % configname, prefix='-I')
+
+ compilable = filter(Compilable, sources)
+ objs = map(self.Objectify, map(self.Absolutify, map(Target, compilable)))
+ self.WriteList(objs, 'OBJS')
+
+ self.WriteLn('# Add to the list of files we specially track '
+ 'dependencies for.')
+ self.WriteLn('all_deps += $(OBJS)')
+ self._num_outputs += len(objs)
+ self.WriteLn()
+
+ # Make sure our dependencies are built first.
+ if deps:
+ self.WriteMakeRule(['$(OBJS)'], deps,
+ comment = 'Make sure our dependencies are built '
+ 'before any of us.',
+ order_only = True)
+
+ # Make sure the actions and rules run first.
+ # If they generate any extra headers etc., the per-.o file dep tracking
+ # will catch the proper rebuilds, so order only is still ok here.
+ if extra_outputs:
+ self.WriteMakeRule(['$(OBJS)'], extra_outputs,
+ comment = 'Make sure our actions/rules run '
+ 'before any of us.',
+ order_only = True)
+
+ if objs:
+ extra_link_deps.append('$(OBJS)')
+ self.WriteLn("""\
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.""")
+ self.WriteLn("$(OBJS): TOOLSET := $(TOOLSET)")
+ self.WriteLn("$(OBJS): GYP_CFLAGS := "
+ "$(DEFS_$(BUILDTYPE)) "
+ "$(INCS_$(BUILDTYPE)) "
+ "$(CFLAGS_$(BUILDTYPE)) "
+ "$(CFLAGS_C_$(BUILDTYPE))")
+ self.WriteLn("$(OBJS): GYP_CXXFLAGS := "
+ "$(DEFS_$(BUILDTYPE)) "
+ "$(INCS_$(BUILDTYPE)) "
+ "$(CFLAGS_$(BUILDTYPE)) "
+ "$(CFLAGS_CC_$(BUILDTYPE))")
+
+ # If there are any object files in our input file list, link them into our
+ # output.
+ extra_link_deps += filter(Linkable, sources)
+
+ self.WriteLn()
+
+
+ def ComputeOutput(self, spec):
+ """Return the 'output' (full output path) of a gyp spec.
+
+ E.g., the loadable module 'foobar' in directory 'baz' will produce
+ '$(obj)/baz/libfoobar.so'
+ """
+ output = None
+ target = spec['target_name']
+ target_prefix = ''
+ target_ext = ''
+ path = os.path.join('$(obj).' + self.toolset, self.path)
+ if self.type == 'static_library':
+ if target[:3] == 'lib':
+ target = target[3:]
+ target_prefix = 'lib'
+ target_ext = '.a'
+ elif self.type in ('loadable_module', 'shared_library'):
+ if target[:3] == 'lib':
+ target = target[3:]
+ target_prefix = 'lib'
+ target_ext = '.so'
+ elif self.type == 'none':
+ target = '%s.stamp' % target
+ elif self.type == 'settings':
+ return None
+ elif self.type == 'executable':
+ path = os.path.join('$(builddir)')
+ else:
+ print ("ERROR: What output file should be generated?",
+ "typ", self.type, "target", target)
+
+ path = spec.get('product_dir', path)
+ target_prefix = spec.get('product_prefix', target_prefix)
+ target = spec.get('product_name', target)
+ product_ext = spec.get('product_extension')
+ if product_ext:
+ target_ext = '.' + product_ext
+
+ return os.path.join(path, target_prefix + target + target_ext)
+
+
+ def ComputeDeps(self, spec):
+ """Compute the dependencies of a gyp spec.
+
+ Returns a tuple (deps, link_deps), where each is a list of
+ filenames that will need to be put in front of make for either
+ building (deps) or linking (link_deps).
+ """
+ deps = []
+ link_deps = []
+ if 'dependencies' in spec:
+ deps.extend([target_outputs[dep] for dep in spec['dependencies']
+ if target_outputs[dep]])
+ for dep in spec['dependencies']:
+ if dep in target_link_deps:
+ link_deps.extend(target_link_deps[dep])
+ deps.extend(link_deps)
+ # TODO: It seems we need to transitively link in libraries (e.g. -lfoo)?
+ # This hack makes it work:
+ # link_deps.extend(spec.get('libraries', []))
+ return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
+
+
+ def WriteTarget(self, spec, configs, deps, link_deps, extra_outputs,
+ part_of_all):
+ """Write Makefile code to produce the final target of the gyp spec.
+
+ spec, configs: input from gyp.
+ deps, link_deps: dependency lists; see ComputeDeps()
+ extra_outputs: any extra outputs that our target should depend on
+ part_of_all: flag indicating this target is part of 'all'
+ """
+
+ self.WriteLn('### Rules for final target.')
+
+ if extra_outputs:
+ self.WriteMakeRule([self.output], extra_outputs,
+ comment = 'Build our special outputs first.',
+ order_only = True)
+ self.WriteMakeRule(extra_outputs, deps,
+ comment=('Preserve order dependency of '
+ 'special output on deps.'),
+ order_only = True,
+ multiple_output_trick = False)
+
+ if self.type not in ('settings', 'none'):
+ for configname in sorted(configs.keys()):
+ config = configs[configname]
+ self.WriteList(config.get('ldflags'), 'LDFLAGS_%s' % configname)
+ libraries = spec.get('libraries')
+ if libraries:
+ # Remove duplicate entries
+ libraries = gyp.common.uniquer(libraries)
+ self.WriteList(libraries, 'LIBS')
+ self.WriteLn('%s: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))' % self.output)
+ self.WriteLn('%s: LIBS := $(LIBS)' % self.output)
+
+ if self.type == 'executable':
+ self.WriteDoCmd([self.output], link_deps, 'link', part_of_all)
+ elif self.type == 'static_library':
+ self.WriteDoCmd([self.output], link_deps, 'alink', part_of_all)
+ elif self.type in ('loadable_module', 'shared_library'):
+ self.WriteDoCmd([self.output], link_deps, 'solink', part_of_all)
+ elif self.type == 'none':
+ # Write a stamp line.
+ self.WriteDoCmd([self.output], deps, 'touch', part_of_all)
+ elif self.type == 'settings':
+ # Only used for passing flags around.
+ pass
+ else:
+ print "WARNING: no output for", self.type, target
+
+ # Add an alias for each target (if there are any outputs).
+ # Installable target aliases are created below.
+ if ((self.output and self.output != self.target) and
+ (self.type not in self._INSTALLABLE_TARGETS)):
+ self.WriteMakeRule([self.target], [self.output],
+ comment='Add target alias', phony = True)
+ if part_of_all:
+ self.WriteMakeRule(['all'], [self.target],
+ comment = 'Add target alias to "all" target.',
+ phony = True)
+
+ # Add special-case rules for our installable targets.
+ # 1) They need to install to the build dir or "product" dir.
+ # 2) They get shortcuts for building (e.g. "make chrome").
+ # 3) They are part of "make all".
+ if self.type in self._INSTALLABLE_TARGETS:
+ if self.type == 'shared_library':
+ file_desc = 'shared library'
+ else:
+ file_desc = 'executable'
+ install_path = self._InstallableTargetInstallPath()
+ installable_deps = [self.output]
+ # Point the target alias to the final binary output.
+ self.WriteMakeRule([self.target], [install_path],
+ comment='Add target alias', phony = True)
+ if install_path != self.output:
+ self.WriteDoCmd([install_path], [self.output], 'copy',
+ comment = 'Copy this to the %s output path.' %
+ file_desc, part_of_all=part_of_all)
+ installable_deps.append(install_path)
+ if self.output != self.alias and self.alias != self.target:
+ self.WriteMakeRule([self.alias], installable_deps,
+ comment = 'Short alias for building this %s.' %
+ file_desc, phony = True)
+ if part_of_all:
+ self.WriteMakeRule(['all'], [install_path],
+ comment = 'Add %s to "all" target.' % file_desc,
+ phony = True)
+
+
+ def WriteList(self, list, variable=None, prefix='', quoter=QuoteIfNecessary):
+ """Write a variable definition that is a list of values.
+
+ E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
+ foo = blaha blahb
+ but in a pretty-printed style.
+ """
+ self.fp.write(variable + " := ")
+ if list:
+ list = [quoter(prefix + l) for l in list]
+ self.fp.write(" \\\n\t".join(list))
+ self.fp.write("\n\n")
+
+
+ def WriteDoCmd(self, outputs, inputs, command, part_of_all, comment=None):
+ """Write a Makefile rule that uses do_cmd.
+
+ This makes the outputs dependent on the command line that was run,
+ as well as support the V= make command line flag.
+ """
+ self.WriteMakeRule(outputs, inputs,
+ actions = ['$(call do_cmd,%s)' % command],
+ comment = comment,
+ force = True)
+ # Add our outputs to the list of targets we read depfiles from.
+ self.WriteLn('all_deps += %s' % ' '.join(outputs))
+ self._num_outputs += len(outputs)
+
+
+ def WriteMakeRule(self, outputs, inputs, actions=None, comment=None,
+ order_only=False, force=False, phony=False,
+ multiple_output_trick=True):
+ """Write a Makefile rule, with some extra tricks.
+
+ outputs: a list of outputs for the rule (note: this is not directly
+ supported by make; see comments below)
+ inputs: a list of inputs for the rule
+ actions: a list of shell commands to run for the rule
+ comment: a comment to put in the Makefile above the rule (also useful
+ for making this Python script's code self-documenting)
+ order_only: if true, makes the dependency order-only
+ force: if true, include FORCE_DO_CMD as an order-only dep
+ phony: if true, the rule does not actually generate the named output, the
+ output is just a name to run the rule
+ multiple_output_trick: if true (the default), perform tricks such as dummy
+ rules to avoid problems with multiple outputs.
+ """
+ if comment:
+ self.WriteLn('# ' + comment)
+ if phony:
+ self.WriteLn('.PHONY: ' + ' '.join(outputs))
+ # TODO(evanm): just make order_only a list of deps instead of these hacks.
+ if order_only:
+ order_insert = '| '
+ else:
+ order_insert = ''
+ if force:
+ force_append = ' FORCE_DO_CMD'
+ else:
+ force_append = ''
+ if actions:
+ self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
+ self.WriteLn('%s: %s%s%s' % (outputs[0], order_insert, ' '.join(inputs),
+ force_append))
+ if actions:
+ for action in actions:
+ self.WriteLn('\t%s' % action)
+ if multiple_output_trick and len(outputs) > 1:
+ # If we have more than one output, a rule like
+ # foo bar: baz
+ # that for *each* output we must run the action, potentially
+ # in parallel. That is not what we're trying to write -- what
+ # we want is that we run the action once and it generates all
+ # the files.
+ # http://www.gnu.org/software/hello/manual/automake/Multiple-Outputs.html
+ # discusses this problem and has this solution:
+ # 1) Write the naive rule that would produce parallel runs of
+ # the action.
+ # 2) Make the outputs seralized on each other, so we won't start
+ # a parallel run until the first run finishes, at which point
+ # we'll have generated all the outputs and we're done.
+ self.WriteLn('%s: %s' % (' '.join(outputs[1:]), outputs[0]))
+ # Add a dummy command to the "extra outputs" rule, otherwise make seems to
+ # think these outputs haven't (couldn't have?) changed, and thus doesn't
+ # flag them as changed (i.e. include in '$?') when evaluating dependent
+ # rules, which in turn causes do_cmd() to skip running dependent commands.
+ self.WriteLn('%s: ;' % (' '.join(outputs[1:])))
+ self.WriteLn()
+
+
+ def WriteLn(self, text=''):
+ self.fp.write(text + '\n')
+
+
+ def Objectify(self, path):
+ """Convert a path to its output directory form."""
+ if '$(' in path:
+ path = path.replace('$(obj)/', '$(obj).%s/$(TARGET)/' % self.toolset)
+ return path
+ return '$(obj).%s/$(TARGET)/%s' % (self.toolset, path)
+
+ def Absolutify(self, path):
+ """Convert a subdirectory-relative path into a base-relative path.
+ Skips over paths that contain variables."""
+ if '$(' in path:
+ return path
+ return os.path.normpath(os.path.join(self.path, path))
+
+
+ def FixupArgPath(self, arg):
+ if '/' in arg or '.h.' in arg:
+ return self.Absolutify(arg)
+ return arg
+
+
+ def ExpandInputRoot(self, template, expansion):
+ if '%(INPUT_ROOT)s' not in template:
+ return template
+ path = template % { 'INPUT_ROOT': expansion }
+ if not os.path.dirname(path):
+ # If it's just the file name, turn it into a path so FixupArgPath()
+ # will know to Absolutify() it.
+ path = os.path.join('.', path)
+ return path
+
+
+ def _InstallableTargetInstallPath(self):
+ """Returns the location of the final output for an installable target."""
+ if self.type == 'shared_library':
+ # Install all shared libs into a common directory (per toolset) for
+ # convenient access with LD_LIBRARY_PATH.
+ return '$(builddir)/lib.%s/%s' % (self.toolset, self.alias)
+ return '$(builddir)/' + self.alias
+
+
+def WriteAutoRegenerationRule(params, root_makefile, makefile_name,
+ build_files):
+ """Write the target to regenerate the Makefile."""
+ options = params['options']
+ build_files_args = [gyp.common.RelativePath(filename, options.toplevel_dir)
+ for filename in params['build_files_arg']]
+ gyp_binary = gyp.common.FixIfRelativePath(params['gyp_binary'],
+ options.toplevel_dir)
+ if not gyp_binary.startswith(os.sep):
+ gyp_binary = os.path.join('.', gyp_binary)
+ root_makefile.write(
+ "quiet_cmd_regen_makefile = ACTION Regenerating $@\n"
+ "cmd_regen_makefile = %(cmd)s\n"
+ "%(makefile_name)s: %(deps)s\n"
+ "\t$(call do_cmd,regen_makefile)\n\n" % {
+ 'makefile_name': makefile_name,
+ 'deps': ' '.join(map(Sourceify, build_files)),
+ 'cmd': gyp.common.EncodePOSIXShellList(
+ [gyp_binary, '-fmake'] +
+ gyp.RegenerateFlags(options) +
+ build_files_args)})
+
+
+def RunSystemTests():
+ """Run tests against the system to compute default settings for commands.
+
+ Returns:
+ dictionary of settings matching the block of command-lines used in
+ SHARED_HEADER. E.g. the dictionary will contain a ARFLAGS.target
+ key for the default ARFLAGS for the target ar command.
+ """
+ # Compute flags used for building static archives.
+ # N.B.: this fallback logic should match the logic in SHARED_HEADER.
+ # See comment there for more details.
+ ar_target = os.environ.get('AR.target', os.environ.get('AR', 'ar'))
+ cc_target = os.environ.get('CC.target', os.environ.get('CC', 'cc'))
+ arflags_target = 'crs'
+ if gyp.system_test.TestArSupportsT(ar_command=ar_target,
+ cc_command=cc_target):
+ arflags_target = 'crsT'
+
+ ar_host = os.environ.get('AR.host', 'ar')
+ cc_host = os.environ.get('CC.host', 'gcc')
+ arflags_host = 'crs'
+ # It feels redundant to compute this again given that most builds aren't
+ # cross-compiles, but due to quirks of history CC.host defaults to 'gcc'
+ # while CC.target defaults to 'cc', so the commands really are different
+ # even though they're nearly guaranteed to run the same code underneath.
+ if gyp.system_test.TestArSupportsT(ar_command=ar_host, cc_command=cc_host):
+ arflags_host = 'crsT'
+
+ link_flags = ''
+ if gyp.system_test.TestLinkerSupportsThreads(cc_command=cc_target):
+ # N.B. we don't test for cross-compilation; as currently written, we
+ # don't even use flock when linking in the cross-compile setup!
+ # TODO(evan): refactor cross-compilation such that this code can
+ # be reused.
+ link_flags = '-Wl,--threads --Wl,--thread-count=4'
+
+ # TODO(evan): cache this output. (But then we'll need to add extra
+ # flags to gyp to flush the cache, yuk! It's fast enough for now to
+ # just run it every time.)
+
+ return { 'ARFLAGS.target': arflags_target,
+ 'ARFLAGS.host': arflags_host,
+ 'LINK_flags': link_flags }
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ options = params['options']
+ generator_flags = params.get('generator_flags', {})
+ builddir_name = generator_flags.get('output_dir', 'out')
+
+ def CalculateMakefilePath(build_file, base_name):
+ """Determine where to write a Makefile for a given gyp file."""
+ # Paths in gyp files are relative to the .gyp file, but we want
+ # paths relative to the source root for the master makefile. Grab
+ # the path of the .gyp file as the base to relativize against.
+ # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
+ base_path = gyp.common.RelativePath(os.path.dirname(build_file),
+ options.depth)
+ # We write the file in the base_path directory.
+ output_file = os.path.join(options.depth, base_path, base_name)
+ if options.generator_output:
+ output_file = os.path.join(options.generator_output, output_file)
+ base_path = gyp.common.RelativePath(os.path.dirname(build_file),
+ options.toplevel_dir)
+ return base_path, output_file
+
+ # TODO: search for the first non-'Default' target. This can go
+ # away when we add verification that all targets have the
+ # necessary configurations.
+ default_configuration = None
+ toolsets = set([target_dicts[target]['toolset'] for target in target_list])
+ for target in target_list:
+ spec = target_dicts[target]
+ if spec['default_configuration'] != 'Default':
+ default_configuration = spec['default_configuration']
+ break
+ if not default_configuration:
+ default_configuration = 'Default'
+
+ srcdir = '.'
+ makefile_name = 'Makefile' + options.suffix
+ makefile_path = os.path.join(options.toplevel_dir, makefile_name)
+ if options.generator_output:
+ global srcdir_prefix
+ makefile_path = os.path.join(options.generator_output, makefile_path)
+ srcdir = gyp.common.RelativePath(srcdir, options.generator_output)
+ srcdir_prefix = '$(srcdir)/'
+
+ header_params = {
+ 'srcdir': srcdir,
+ 'builddir': builddir_name,
+ 'default_configuration': default_configuration,
+ }
+ header_params.update(RunSystemTests())
+
+ ensure_directory_exists(makefile_path)
+ root_makefile = open(makefile_path, 'w')
+ root_makefile.write(SHARED_HEADER % header_params)
+ for toolset in toolsets:
+ root_makefile.write('TOOLSET := %s\n' % toolset)
+ root_makefile.write(ROOT_HEADER_SUFFIX_RULES)
+
+ # Find the list of targets that derive from the gyp file(s) being built.
+ needed_targets = set()
+ for build_file in params['build_files']:
+ for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
+ needed_targets.add(target)
+
+ num_outputs = 0
+ build_files = set()
+ include_list = set()
+ for qualified_target in target_list:
+ build_file, target, toolset = gyp.common.ParseQualifiedTarget(
+ qualified_target)
+ build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
+ included_files = data[build_file]['included_files']
+ for included_file in included_files:
+ # The included_files entries are relative to the dir of the build file
+ # that included them, so we have to undo that and then make them relative
+ # to the root dir.
+ relative_include_file = gyp.common.RelativePath(
+ gyp.common.UnrelativePath(included_file, build_file),
+ options.toplevel_dir)
+ abs_include_file = os.path.abspath(relative_include_file)
+ # If the include file is from the ~/.gyp dir, we should use absolute path
+ # so that relocating the src dir doesn't break the path.
+ if (params['home_dot_gyp'] and
+ abs_include_file.startswith(params['home_dot_gyp'])):
+ build_files.add(abs_include_file)
+ else:
+ build_files.add(relative_include_file)
+
+ base_path, output_file = CalculateMakefilePath(build_file,
+ target + '.' + toolset + options.suffix + '.mk')
+
+ spec = target_dicts[qualified_target]
+ configs = spec['configurations']
+
+ writer = MakefileWriter()
+ writer.Write(qualified_target, base_path, output_file, spec, configs,
+ part_of_all=qualified_target in needed_targets)
+ num_outputs += writer.NumOutputs()
+
+ # Our root_makefile lives at the source root. Compute the relative path
+ # from there to the output_file for including.
+ mkfile_rel_path = gyp.common.RelativePath(output_file,
+ os.path.dirname(makefile_path))
+ include_list.add(mkfile_rel_path)
+
+ # Write out per-gyp (sub-project) Makefiles.
+ depth_rel_path = gyp.common.RelativePath(options.depth, os.getcwd())
+ for build_file in build_files:
+ # The paths in build_files were relativized above, so undo that before
+ # testing against the non-relativized items in target_list and before
+ # calculating the Makefile path.
+ build_file = os.path.join(depth_rel_path, build_file)
+ gyp_targets = [target_dicts[target]['target_name'] for target in target_list
+ if target.startswith(build_file) and
+ target in needed_targets]
+ # Only generate Makefiles for gyp files with targets.
+ if not gyp_targets:
+ continue
+ base_path, output_file = CalculateMakefilePath(build_file,
+ os.path.splitext(os.path.basename(build_file))[0] + '.Makefile')
+ makefile_rel_path = gyp.common.RelativePath(os.path.dirname(makefile_path),
+ os.path.dirname(output_file))
+ writer.WriteSubMake(output_file, makefile_rel_path, gyp_targets,
+ builddir_name)
+
+
+ # Write out the sorted list of includes.
+ root_makefile.write('\n')
+ for include_file in sorted(include_list):
+ # We wrap each .mk include in an if statement so users can tell make to
+ # not load a file by setting NO_LOAD. The below make code says, only
+ # load the .mk file if the .mk filename doesn't start with a token in
+ # NO_LOAD.
+ root_makefile.write(
+ "ifeq ($(strip $(foreach prefix,$(NO_LOAD),\\\n"
+ " $(findstring $(join ^,$(prefix)),\\\n"
+ " $(join ^," + include_file + ")))),)\n")
+ root_makefile.write(" include " + include_file + "\n")
+ root_makefile.write("endif\n")
+ root_makefile.write('\n')
+
+ if generator_flags.get('auto_regeneration', True):
+ WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
+
+ # Write the rule to load dependencies. We batch 1000 files at a time to
+ # avoid overflowing the command line.
+ all_deps = ""
+ for i in range(1001, num_outputs, 1000):
+ all_deps += ("""
+ ifneq ($(word %(start)d,$(d_files)),)
+ $(shell cat $(wordlist %(start)d,%(end)d,$(d_files)) >> $(depsdir)/all.deps)
+ endif""" % { 'start': i, 'end': i + 999 })
+
+ # Add a check to make sure we tried to process all the .d files.
+ all_deps += """
+ ifneq ($(word %(last)d,$(d_files)),)
+ $(error Found unprocessed dependency files (gyp didn't generate enough rules!))
+ endif
+""" % { 'last': ((num_outputs / 1000) + 1) * 1000 + 1 }
+
+ root_makefile.write(SHARED_FOOTER % { 'generate_all_deps': all_deps })
+
+ root_makefile.close()
diff --git a/Source/ThirdParty/gyp/pylib/gyp/generator/msvs.py b/Source/ThirdParty/gyp/pylib/gyp/generator/msvs.py
new file mode 100644
index 000000000..f7153e687
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/generator/msvs.py
@@ -0,0 +1,1541 @@
+#!/usr/bin/python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import ntpath
+import posixpath
+import os
+import re
+import subprocess
+import sys
+
+import gyp.MSVSNew as MSVSNew
+import gyp.MSVSProject as MSVSProject
+import gyp.MSVSToolFile as MSVSToolFile
+import gyp.MSVSUserFile as MSVSUserFile
+import gyp.MSVSVersion as MSVSVersion
+import gyp.MSVSSettings as MSVSSettings
+import gyp.common
+
+
+# Regular expression for validating Visual Studio GUIDs. If the GUID
+# contains lowercase hex letters, MSVS will be fine. However,
+# IncrediBuild BuildConsole will parse the solution file, but then
+# silently skip building the target causing hard to track down errors.
+# Note that this only happens with the BuildConsole, and does not occur
+# if IncrediBuild is executed from inside Visual Studio. This regex
+# validates that the string looks like a GUID with all uppercase hex
+# letters.
+VALID_MSVS_GUID_CHARS = re.compile('^[A-F0-9\-]+$')
+
+
+generator_default_variables = {
+ 'EXECUTABLE_PREFIX': '',
+ 'EXECUTABLE_SUFFIX': '.exe',
+ 'STATIC_LIB_PREFIX': '',
+ 'SHARED_LIB_PREFIX': '',
+ 'STATIC_LIB_SUFFIX': '.lib',
+ 'SHARED_LIB_SUFFIX': '.dll',
+ 'INTERMEDIATE_DIR': '$(IntDir)',
+ 'SHARED_INTERMEDIATE_DIR': '$(OutDir)/obj/global_intermediate',
+ 'OS': 'win',
+ 'PRODUCT_DIR': '$(OutDir)',
+ 'LIB_DIR': '$(OutDir)/lib',
+ 'RULE_INPUT_ROOT': '$(InputName)',
+ 'RULE_INPUT_EXT': '$(InputExt)',
+ 'RULE_INPUT_NAME': '$(InputFileName)',
+ 'RULE_INPUT_PATH': '$(InputPath)',
+ 'CONFIGURATION_NAME': '$(ConfigurationName)',
+}
+
+
+# The msvs specific sections that hold paths
+generator_additional_path_sections = [
+ 'msvs_cygwin_dirs',
+ 'msvs_props',
+]
+
+generator_additional_non_configuration_keys = [
+ 'msvs_cygwin_dirs',
+ 'msvs_cygwin_shell',
+]
+
+# List of precompiled header related keys.
+precomp_keys = [
+ 'msvs_precompiled_header',
+ 'msvs_precompiled_source',
+]
+
+cached_username = None
+cached_domain = None
+
+# TODO(gspencer): Switch the os.environ calls to be
+# win32api.GetDomainName() and win32api.GetUserName() once the
+# python version in depot_tools has been updated to work on Vista
+# 64-bit.
+def _GetDomainAndUserName():
+ if sys.platform not in ('win32', 'cygwin'):
+ return ('DOMAIN', 'USERNAME')
+ global cached_username
+ global cached_domain
+ if not cached_domain or not cached_username:
+ domain = os.environ.get('USERDOMAIN')
+ username = os.environ.get('USERNAME')
+ if not domain or not username:
+ call = subprocess.Popen(['net', 'config', 'Workstation'],
+ stdout=subprocess.PIPE)
+ config = call.communicate()[0]
+ username_re = re.compile('^User name\s+(\S+)', re.MULTILINE)
+ username_match = username_re.search(config)
+ if username_match:
+ username = username_match.group(1)
+ domain_re = re.compile('^Logon domain\s+(\S+)', re.MULTILINE)
+ domain_match = domain_re.search(config)
+ if domain_match:
+ domain = domain_match.group(1)
+ cached_domain = domain
+ cached_username = username
+ return (cached_domain, cached_username)
+
+fixpath_prefix = None
+
+
+def _NormalizedSource(source):
+ """ Normalize the path.
+
+ But not if that gets rid of a variable, as this may expand to something
+ larger than one directory.
+ """
+ normalized = os.path.normpath(source)
+ if source.count('$') == normalized.count('$'):
+ source = normalized
+ return source
+
+
+def _FixPath(path):
+ """Convert paths to a form that will make sense in a vcproj file.
+
+ Arguments:
+ path: The path to convert, may contain / etc.
+ Returns:
+ The path with all slashes made into backslashes.
+ """
+ if fixpath_prefix and path and not os.path.isabs(path) and not path[0] == '$':
+ path = os.path.join(fixpath_prefix, path)
+ path = path.replace('/', '\\')
+ path = _NormalizedSource(path)
+ if len(path) > 0 and path[-1] == '\\':
+ path = path[:-1]
+ return path
+
+
+def _ConvertSourcesToFilterHierarchy(sources, prefix=None, excluded=None):
+ """Converts a list split source file paths into a vcproj folder hierarchy.
+
+ Arguments:
+ sources: A list of source file paths split.
+ prefix: A list of source file path layers meant to apply to each of sources.
+ Returns:
+ A hierarchy of filenames and MSVSProject.Filter objects that matches the
+ layout of the source tree.
+ For example:
+ _ConvertSourcesToFilterHierarchy([['a', 'bob1.c'], ['b', 'bob2.c']],
+ prefix=['joe'])
+ -->
+ [MSVSProject.Filter('a', contents=['joe\\a\\bob1.c']),
+ MSVSProject.Filter('b', contents=['joe\\b\\bob2.c'])]
+ """
+ if not prefix: prefix = []
+ result = []
+ excluded_result = []
+ folders = dict()
+ # Gather files into the final result, excluded, or folders.
+ for s in sources:
+ if len(s) == 1:
+ filename = _NormalizedSource('\\'.join(prefix + s))
+ if filename in excluded:
+ excluded_result.append(filename)
+ else:
+ result.append(filename)
+ else:
+ if not folders.get(s[0]):
+ folders[s[0]] = []
+ folders[s[0]].append(s[1:])
+ # Add a folder for excluded files.
+ if excluded_result:
+ excluded_folder = MSVSProject.Filter('_excluded_files',
+ contents=excluded_result)
+ result.append(excluded_folder)
+ # Populate all the folders.
+ for f in folders:
+ contents = _ConvertSourcesToFilterHierarchy(folders[f], prefix=prefix + [f],
+ excluded=excluded)
+ contents = MSVSProject.Filter(f, contents=contents)
+ result.append(contents)
+
+ return result
+
+
+def _ToolAppend(tools, tool_name, setting, value, only_if_unset=False):
+ if not value: return
+ # TODO(bradnelson): ugly hack, fix this more generally!!!
+ if 'Directories' in setting or 'Dependencies' in setting:
+ if type(value) == str:
+ value = value.replace('/', '\\')
+ else:
+ value = [i.replace('/', '\\') for i in value]
+ if not tools.get(tool_name):
+ tools[tool_name] = dict()
+ tool = tools[tool_name]
+ if tool.get(setting):
+ if only_if_unset: return
+ if type(tool[setting]) == list:
+ tool[setting] += value
+ else:
+ raise TypeError(
+ 'Appending "%s" to a non-list setting "%s" for tool "%s" is '
+ 'not allowed, previous value: %s' % (
+ value, setting, tool_name, str(tool[setting])))
+ else:
+ tool[setting] = value
+
+
+def _ConfigPlatform(config_data):
+ return config_data.get('msvs_configuration_platform', 'Win32')
+
+
+def _ConfigBaseName(config_name, platform_name):
+ if config_name.endswith('_' + platform_name):
+ return config_name[0:-len(platform_name)-1]
+ else:
+ return config_name
+
+
+def _ConfigFullName(config_name, config_data):
+ platform_name = _ConfigPlatform(config_data)
+ return '%s|%s' % (_ConfigBaseName(config_name, platform_name), platform_name)
+
+
+def _BuildCommandLineForRuleRaw(spec, cmd, cygwin_shell, has_input_path,
+ quote_cmd):
+ if cygwin_shell:
+ # Find path to cygwin.
+ cygwin_dir = _FixPath(spec.get('msvs_cygwin_dirs', ['.'])[0])
+ # Prepare command.
+ direct_cmd = cmd
+ direct_cmd = [i.replace('$(IntDir)',
+ '`cygpath -m "${INTDIR}"`') for i in direct_cmd]
+ direct_cmd = [i.replace('$(OutDir)',
+ '`cygpath -m "${OUTDIR}"`') for i in direct_cmd]
+ if has_input_path:
+ direct_cmd = [i.replace('$(InputPath)',
+ '`cygpath -m "${INPUTPATH}"`')
+ for i in direct_cmd]
+ direct_cmd = ['"%s"' % i for i in direct_cmd]
+ direct_cmd = [i.replace('"', '\\"') for i in direct_cmd]
+ #direct_cmd = gyp.common.EncodePOSIXShellList(direct_cmd)
+ direct_cmd = ' '.join(direct_cmd)
+ # TODO(quote): regularize quoting path names throughout the module
+ cmd = (
+ 'call "$(ProjectDir)%(cygwin_dir)s\\setup_env.bat" && '
+ 'set CYGWIN=nontsec&& ')
+ if direct_cmd.find('NUMBER_OF_PROCESSORS') >= 0:
+ cmd += 'set /a NUMBER_OF_PROCESSORS_PLUS_1=%%NUMBER_OF_PROCESSORS%%+1&& '
+ if direct_cmd.find('INTDIR') >= 0:
+ cmd += 'set INTDIR=$(IntDir)&& '
+ if direct_cmd.find('OUTDIR') >= 0:
+ cmd += 'set OUTDIR=$(OutDir)&& '
+ if has_input_path and direct_cmd.find('INPUTPATH') >= 0:
+ cmd += 'set INPUTPATH=$(InputPath) && '
+ cmd += (
+ 'bash -c "%(cmd)s"')
+ cmd = cmd % {'cygwin_dir': cygwin_dir,
+ 'cmd': direct_cmd}
+ return cmd
+ else:
+ # Convert cat --> type to mimic unix.
+ if cmd[0] == 'cat':
+ command = ['type']
+ else:
+ command = [cmd[0].replace('/', '\\')]
+ # Fix the paths
+ # If the argument starts with a slash, it's probably a command line switch
+ arguments = [i.startswith('/') and i or _FixPath(i) for i in cmd[1:]]
+ if quote_cmd:
+ # Support a mode for using cmd directly.
+ # Convert any paths to native form (first element is used directly).
+ # TODO(quote): regularize quoting path names throughout the module
+ arguments = ['"%s"' % i for i in arguments]
+ # Collapse into a single command.
+ return ' '.join(command + arguments)
+
+
+def _BuildCommandLineForRule(spec, rule, has_input_path):
+ # Find path to cygwin.
+ cygwin_dir = _FixPath(spec.get('msvs_cygwin_dirs', ['.'])[0])
+
+ # Currently this weird argument munging is used to duplicate the way a
+ # python script would need to be run as part of the chrome tree.
+ # Eventually we should add some sort of rule_default option to set this
+ # per project. For now the behavior chrome needs is the default.
+ mcs = rule.get('msvs_cygwin_shell')
+ if mcs is None:
+ mcs = int(spec.get('msvs_cygwin_shell', 1))
+ elif isinstance(mcs, str):
+ mcs = int(mcs)
+ quote_cmd = int(rule.get('msvs_quote_cmd', 1))
+ return _BuildCommandLineForRuleRaw(spec, rule['action'], mcs, has_input_path,
+ quote_cmd)
+
+
+def _AddActionStep(actions_dict, inputs, outputs, description, command):
+ """Merge action into an existing list of actions.
+
+ Care must be taken so that actions which have overlapping inputs either don't
+ get assigned to the same input, or get collapsed into one.
+
+ Arguments:
+ actions_dict: dictionary keyed on input name, which maps to a list of
+ dicts describing the actions attached to that input file.
+ inputs: list of inputs
+ outputs: list of outputs
+ description: description of the action
+ command: command line to execute
+ """
+ # Require there to be at least one input (call sites will ensure this).
+ assert inputs
+
+ action = {
+ 'inputs': inputs,
+ 'outputs': outputs,
+ 'description': description,
+ 'command': command,
+ }
+
+ # Pick where to stick this action.
+ # While less than optimal in terms of build time, attach them to the first
+ # input for now.
+ chosen_input = inputs[0]
+
+ # Add it there.
+ if chosen_input not in actions_dict:
+ actions_dict[chosen_input] = []
+ actions_dict[chosen_input].append(action)
+
+
+def _AddCustomBuildToolForMSVS(p, spec, primary_input,
+ inputs, outputs, description, cmd):
+ """Add a custom build tool to execute something.
+
+ Arguments:
+ p: the target project
+ spec: the target project dict
+ primary_input: input file to attach the build tool to
+ inputs: list of inputs
+ outputs: list of outputs
+ description: description of the action
+ cmd: command line to execute
+ """
+ inputs = [_FixPath(i) for i in inputs]
+ outputs = [_FixPath(i) for i in outputs]
+ tool = MSVSProject.Tool(
+ 'VCCustomBuildTool', {
+ 'Description': description,
+ 'AdditionalDependencies': ';'.join(inputs),
+ 'Outputs': ';'.join(outputs),
+ 'CommandLine': cmd,
+ })
+ # Add to the properties of primary input for each config.
+ for config_name, c_data in spec['configurations'].iteritems():
+ p.AddFileConfig(_FixPath(primary_input),
+ _ConfigFullName(config_name, c_data), tools=[tool])
+
+
+def _AddAccumulatedActionsToMSVS(p, spec, actions_dict):
+ """Add actions accumulated into an actions_dict, merging as needed.
+
+ Arguments:
+ p: the target project
+ spec: the target project dict
+ actions_dict: dictionary keyed on input name, which maps to a list of
+ dicts describing the actions attached to that input file.
+ """
+ for input in actions_dict:
+ inputs = set()
+ outputs = set()
+ descriptions = []
+ commands = []
+ for action in actions_dict[input]:
+ inputs.update(set(action['inputs']))
+ outputs.update(set(action['outputs']))
+ descriptions.append(action['description'])
+ commands.append(action['command'])
+ # Add the custom build step for one input file.
+ description = ', and also '.join(descriptions)
+ command = '\r\n'.join(commands)
+ _AddCustomBuildToolForMSVS(p, spec,
+ primary_input=input,
+ inputs=inputs,
+ outputs=outputs,
+ description=description,
+ cmd=command)
+
+
+def _RuleExpandPath(path, input_file):
+ """Given the input file to which a rule applied, string substitute a path.
+
+ Arguments:
+ path: a path to string expand
+ input_file: the file to which the rule applied.
+ Returns:
+ The string substituted path.
+ """
+ path = path.replace('$(InputName)',
+ os.path.splitext(os.path.split(input_file)[1])[0])
+ path = path.replace('$(InputExt)',
+ os.path.splitext(os.path.split(input_file)[1])[1])
+ path = path.replace('$(InputFileName)', os.path.split(input_file)[1])
+ path = path.replace('$(InputPath)', input_file)
+ return path
+
+
+def _FindRuleTriggerFiles(rule, sources):
+ """Find the list of files which a particular rule applies to.
+
+ Arguments:
+ rule: the rule in question
+ sources: the set of all known source files for this project
+ Returns:
+ The list of sources that trigger a particular rule.
+ """
+ rule_ext = rule['extension']
+ return [s for s in sources if s.endswith('.' + rule_ext)]
+
+
+def _RuleInputsAndOutputs(rule, trigger_file):
+ """Find the inputs and outputs generated by a rule.
+
+ Arguments:
+ rule: the rule in question
+ sources: the set of all known source files for this project
+ Returns:
+ The pair of (inputs, outputs) involved in this rule.
+ """
+ raw_inputs = [_FixPath(i) for i in rule.get('inputs', [])]
+ raw_outputs = [_FixPath(i) for i in rule.get('outputs', [])]
+ inputs = set()
+ outputs = set()
+ inputs.add(trigger_file)
+ for i in raw_inputs:
+ inputs.add(_RuleExpandPath(i, trigger_file))
+ for o in raw_outputs:
+ outputs.add(_RuleExpandPath(o, trigger_file))
+ return (inputs, outputs)
+
+
+def _GenerateNativeRulesForMSVS(p, rules, output_dir, spec, options):
+ """Generate a native rules file.
+
+ Arguments:
+ p: the target project
+ rules: the set of rules to include
+ output_dir: the directory in which the project/gyp resides
+ spec: the project dict
+ options: global generator options
+ """
+ rules_filename = '%s%s.rules' % (spec['target_name'],
+ options.suffix)
+ rules_file = MSVSToolFile.Writer(os.path.join(output_dir, rules_filename))
+ rules_file.Create(spec['target_name'])
+ # Add each rule.
+ for r in rules:
+ rule_name = r['rule_name']
+ rule_ext = r['extension']
+ inputs = [_FixPath(i) for i in r.get('inputs', [])]
+ outputs = [_FixPath(i) for i in r.get('outputs', [])]
+ cmd = _BuildCommandLineForRule(spec, r, has_input_path=True)
+ rules_file.AddCustomBuildRule(name=rule_name,
+ description=r.get('message', rule_name),
+ extensions=[rule_ext],
+ additional_dependencies=inputs,
+ outputs=outputs,
+ cmd=cmd)
+ # Write out rules file.
+ rules_file.Write()
+
+ # Add rules file to project.
+ p.AddToolFile(rules_filename)
+
+
+def _Cygwinify(path):
+ path = path.replace('$(OutDir)', '$(OutDirCygwin)')
+ path = path.replace('$(IntDir)', '$(IntDirCygwin)')
+ return path
+
+
+def _GenerateExternalRules(rules, output_dir, spec,
+ sources, options, actions_to_add):
+ """Generate an external makefile to do a set of rules.
+
+ Arguments:
+ rules: the list of rules to include
+ output_dir: path containing project and gyp files
+ spec: project specification data
+ sources: set of sources known
+ options: global generator options
+ """
+ filename = '%s_rules%s.mk' % (spec['target_name'], options.suffix)
+ file = gyp.common.WriteOnDiff(os.path.join(output_dir, filename))
+ # Find cygwin style versions of some paths.
+ file.write('OutDirCygwin:=$(shell cygpath -u "$(OutDir)")\n')
+ file.write('IntDirCygwin:=$(shell cygpath -u "$(IntDir)")\n')
+ # Gather stuff needed to emit all: target.
+ all_inputs = set()
+ all_outputs = set()
+ all_output_dirs = set()
+ first_outputs = []
+ for rule in rules:
+ trigger_files = _FindRuleTriggerFiles(rule, sources)
+ for tf in trigger_files:
+ inputs, outputs = _RuleInputsAndOutputs(rule, tf)
+ all_inputs.update(set(inputs))
+ all_outputs.update(set(outputs))
+ # Only use one target from each rule as the dependency for
+ # 'all' so we don't try to build each rule multiple times.
+ first_outputs.append(list(outputs)[0])
+ # Get the unique output directories for this rule.
+ output_dirs = [os.path.split(i)[0] for i in outputs]
+ for od in output_dirs:
+ all_output_dirs.add(od)
+ first_outputs_cyg = [_Cygwinify(i) for i in first_outputs]
+ # Write out all: target, including mkdir for each output directory.
+ file.write('all: %s\n' % ' '.join(first_outputs_cyg))
+ for od in all_output_dirs:
+ file.write('\tmkdir -p %s\n' % od)
+ file.write('\n')
+ # Define how each output is generated.
+ for rule in rules:
+ trigger_files = _FindRuleTriggerFiles(rule, sources)
+ for tf in trigger_files:
+ # Get all the inputs and outputs for this rule for this trigger file.
+ inputs, outputs = _RuleInputsAndOutputs(rule, tf)
+ inputs = [_Cygwinify(i) for i in inputs]
+ outputs = [_Cygwinify(i) for i in outputs]
+ # Prepare the command line for this rule.
+ cmd = [_RuleExpandPath(c, tf) for c in rule['action']]
+ cmd = ['"%s"' % i for i in cmd]
+ cmd = ' '.join(cmd)
+ # Add it to the makefile.
+ file.write('%s: %s\n' % (' '.join(outputs), ' '.join(inputs)))
+ file.write('\t%s\n\n' % cmd)
+ # Close up the file.
+ file.close()
+
+ # Add makefile to list of sources.
+ sources.add(filename)
+ # Add a build action to call makefile.
+ cmd = ['make',
+ 'OutDir=$(OutDir)',
+ 'IntDir=$(IntDir)',
+ '-j', '${NUMBER_OF_PROCESSORS_PLUS_1}',
+ '-f', filename]
+ cmd = _BuildCommandLineForRuleRaw(spec, cmd, True, False, True)
+ # Insert makefile as 0'th input, so it gets the action attached there,
+ # as this is easier to understand from in the IDE.
+ all_inputs = list(all_inputs)
+ all_inputs.insert(0, filename)
+ _AddActionStep(actions_to_add,
+ inputs=[_FixPath(i) for i in all_inputs],
+ outputs=[_FixPath(i) for i in all_outputs],
+ description='Running %s' % cmd,
+ command=cmd)
+
+
+def _EscapeEnvironmentVariableExpansion(s):
+ """Escapes any % characters so that Windows-style environment variable
+ expansions will leave them alone.
+ See http://connect.microsoft.com/VisualStudio/feedback/details/106127/cl-d-name-text-containing-percentage-characters-doesnt-compile
+ to understand why we have to do this."""
+ s = s.replace('%', '%%')
+ return s
+
+
+quote_replacer_regex = re.compile(r'(\\*)"')
+def _EscapeCommandLineArgumentForMSVS(s):
+ """Escapes a Windows command-line argument, so that the Win32
+ CommandLineToArgv function will turn the escaped result back into the
+ original string. See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+ ("Parsing C++ Command-Line Arguments") to understand why we have to do
+ this."""
+ def replace(match):
+ # For a literal quote, CommandLineToArgv requires an odd number of
+ # backslashes preceding it, and it produces half as many literal backslashes
+ # (rounded down). So we need to produce 2n+1 backslashes.
+ return 2 * match.group(1) + '\\"'
+ # Escape all quotes so that they are interpreted literally.
+ s = quote_replacer_regex.sub(replace, s)
+ # Now add unescaped quotes so that any whitespace is interpreted literally.
+ s = '"' + s + '"'
+ return s
+
+
+delimiters_replacer_regex = re.compile(r'(\\*)([,;]+)')
+def _EscapeVCProjCommandLineArgListItem(s):
+ """The VCProj format stores string lists in a single string using commas and
+ semi-colons as separators, which must be quoted if they are to be
+ interpreted literally. However, command-line arguments may already have
+ quotes, and the VCProj parser is ignorant of the backslash escaping
+ convention used by CommandLineToArgv, so the command-line quotes and the
+ VCProj quotes may not be the same quotes. So to store a general
+ command-line argument in a VCProj list, we need to parse the existing
+ quoting according to VCProj's convention and quote any delimiters that are
+ not already quoted by that convention. The quotes that we add will also be
+ seen by CommandLineToArgv, so if backslashes precede them then we also have
+ to escape those backslashes according to the CommandLineToArgv
+ convention."""
+ def replace(match):
+ # For a non-literal quote, CommandLineToArgv requires an even number of
+ # backslashes preceding it, and it produces half as many literal
+ # backslashes. So we need to produce 2n backslashes.
+ return 2 * match.group(1) + '"' + match.group(2) + '"'
+ list = s.split('"')
+ # The unquoted segments are at the even-numbered indices.
+ for i in range(0, len(list), 2):
+ list[i] = delimiters_replacer_regex.sub(replace, list[i])
+ # Concatenate back into a single string
+ s = '"'.join(list)
+ if len(list) % 2 == 0:
+ # String ends while still quoted according to VCProj's convention. This
+ # means the delimiter and the next list item that follow this one in the
+ # .vcproj file will be misinterpreted as part of this item. There is nothing
+ # we can do about this. Adding an extra quote would correct the problem in
+ # the VCProj but cause the same problem on the final command-line. Moving
+ # the item to the end of the list does works, but that's only possible if
+ # there's only one such item. Let's just warn the user.
+ print >> sys.stderr, ('Warning: MSVS may misinterpret the odd number of ' +
+ 'quotes in ' + s)
+ return s
+
+
+def _EscapeCppDefineForMSVS(s):
+ """Escapes a CPP define so that it will reach the compiler unaltered."""
+ s = _EscapeEnvironmentVariableExpansion(s)
+ s = _EscapeCommandLineArgumentForMSVS(s)
+ s = _EscapeVCProjCommandLineArgListItem(s)
+ return s
+
+
+def _GenerateRulesForMSVS(p, output_dir, options, spec,
+ sources, excluded_sources,
+ actions_to_add):
+ """Generate all the rules for a particular project.
+
+ Arguments:
+ output_dir: directory to emit rules to
+ options: global options passed to the generator
+ spec: the specification for this project
+ sources: the set of all known source files in this project
+ excluded_sources: the set of sources excluded from normal processing
+ actions_to_add: deferred list of actions to add in
+ """
+ rules = spec.get('rules', [])
+ rules_native = [r for r in rules if not int(r.get('msvs_external_rule', 0))]
+ rules_external = [r for r in rules if int(r.get('msvs_external_rule', 0))]
+
+ # Handle rules that use a native rules file.
+ if rules_native:
+ _GenerateNativeRulesForMSVS(p, rules_native, output_dir, spec, options)
+
+ # Handle external rules (non-native rules).
+ if rules_external:
+ _GenerateExternalRules(rules_external, output_dir, spec,
+ sources, options, actions_to_add)
+ _AdjustSourcesForRules(rules, sources, excluded_sources)
+
+
+def _AdjustSourcesForRules(rules, sources, excluded_sources):
+ # Add outputs generated by each rule (if applicable).
+ for rule in rules:
+ # Done if not processing outputs as sources.
+ if int(rule.get('process_outputs_as_sources', False)):
+ # Add in the outputs from this rule.
+ trigger_files = _FindRuleTriggerFiles(rule, sources)
+ for trigger_file in trigger_files:
+ inputs, outputs = _RuleInputsAndOutputs(rule, trigger_file)
+ inputs = set([_FixPath(i) for i in inputs])
+ outputs = set([_FixPath(i) for i in outputs])
+ inputs.remove(_FixPath(trigger_file))
+ sources.update(inputs)
+ excluded_sources.update(inputs)
+ sources.update(outputs)
+
+
+def _FilterActionsFromExcluded(excluded_sources, actions_to_add):
+ """Take inputs with actions attached out of the list of exclusions.
+
+ Arguments:
+ excluded_sources: list of source files not to be built.
+ actions_to_add: dict of actions keyed on source file they're attached to.
+ Returns:
+ excluded_sources with files that have actions attached removed.
+ """
+ must_keep = set([_FixPath(s) for s in actions_to_add.keys()])
+ return [s for s in excluded_sources if s not in must_keep]
+
+
+def _GetDefaultConfiguration(spec):
+ return spec['configurations'][spec['default_configuration']]
+
+
+def _GetGuidOfProject(proj_path, spec):
+ """Get the guid for the project
+
+ Arguments:
+ proj_path: Path of the vcproj file to generate.
+ spec: The target dictionary containing the properties of the target.
+ """
+ # Pluck out the default configuration.
+ default_config = _GetDefaultConfiguration(spec)
+ # Decide the guid of the project.
+ guid = default_config.get('msvs_guid')
+ if guid:
+ if VALID_MSVS_GUID_CHARS.match(guid) == None:
+ raise ValueError('Invalid MSVS guid: "%s". Must match regex: "%s".' %
+ (guid, VALID_MSVS_GUID_CHARS.pattern))
+ guid = '{%s}' % guid
+ guid = guid or MSVSNew.MakeGuid(proj_path)
+ return guid
+
+
+def _GenerateProject(project, options, version):
+ """Generates a vcproj file.
+
+ Arguments:
+ project: the MSVSProject object.
+ options: global generator options.
+ version: the MSVSVersion object.
+"""
+ default_config = _GetDefaultConfiguration(project.spec)
+
+ # Skip emitting anything if told to with msvs_existing_vcproj option.
+ if default_config.get('msvs_existing_vcproj'):
+ return
+
+ _GenerateMSVSProject(project, options, version)
+
+
+def _GenerateMSVSProject(project, options, version):
+ """Generates a .vcproj file. It may create .rules and .user files too.
+
+ Arguments:
+ project: The project object we will generate the file for.
+ options: Global options passed to the generator.
+ version: The VisualStudioVersion object.
+ """
+ spec = project.spec
+ vcproj_dir = os.path.dirname(project.path)
+ if vcproj_dir and not os.path.exists(vcproj_dir):
+ os.makedirs(vcproj_dir)
+
+ platforms = _GetUniquePlatforms(spec)
+ p = MSVSProject.Writer(project.path, version=version)
+ p.Create(spec['target_name'], guid=project.guid, platforms=platforms)
+
+ # Get directory project file is in.
+ gyp_dir = os.path.split(project.path)[0]
+ gyp_file = posixpath.split(project.build_file)[1]
+ gyp_path = _NormalizedSource(gyp_file)
+ relative_path_of_gyp_file = gyp.common.RelativePath(gyp_path, gyp_dir)
+
+ config_type = _GetMSVSConfigurationType(spec, project.build_file)
+ for config_name, config in spec['configurations'].iteritems():
+ _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config)
+
+ # Prepare list of sources and excluded sources.
+ sources, excluded_sources = _PrepareListOfSources(project, spec,
+ relative_path_of_gyp_file)
+
+ # Add rules.
+ actions_to_add = {}
+ _GenerateRulesForMSVS(p, gyp_dir, options, spec,
+ sources, excluded_sources,
+ actions_to_add)
+ sources, excluded_sources, excluded_idl = (
+ _AdjustSourcesAndConvertToFilterHierarchy(
+ spec, options, gyp_dir, sources, excluded_sources))
+
+ # Add in files.
+ p.AddFiles(sources)
+
+ _AddToolFilesToMSVS(p, spec)
+ _HandlePreCompileHeaderStubs(p, spec)
+ _AddActions(actions_to_add, spec, relative_path_of_gyp_file)
+ _AddCopies(actions_to_add, spec)
+ _WriteMSVSUserFile(project.path, version, spec)
+
+ # NOTE: this stanza must appear after all actions have been decided.
+ # Don't excluded sources with actions attached, or they won't run.
+ excluded_sources = _FilterActionsFromExcluded(
+ excluded_sources, actions_to_add)
+ _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl)
+ _AddAccumulatedActionsToMSVS(p, spec, actions_to_add)
+
+ # Write it out.
+ p.Write()
+
+
+def _GetUniquePlatforms(spec):
+ """Return the list of unique platforms for this spec, e.g ['win32', ...]
+
+ Arguments:
+ spec: The target dictionary containing the properties of the target.
+ Returns:
+ The MSVSUserFile object created.
+ """
+ # Gather list of unique platforms.
+ platforms = set()
+ for configuration in spec['configurations']:
+ platforms.add(_ConfigPlatform(spec['configurations'][configuration]))
+ platforms = list(platforms)
+ return platforms
+
+
+def _CreateMSVSUserFile(proj_path, version, spec):
+ """Generates a .user file for the user running this Gyp program.
+
+ Arguments:
+ proj_path: The path of the project file being created. The .user file
+ shares the same path (with an appropriate suffix).
+ version: The VisualStudioVersion object.
+ spec: The target dictionary containing the properties of the target.
+ Returns:
+ The MSVSUserFile object created.
+ """
+ (domain, username) = _GetDomainAndUserName()
+ vcuser_filename = '.'.join([proj_path, domain, username, 'user'])
+ user_file = MSVSUserFile.Writer(vcuser_filename, version=version)
+ user_file.Create(spec['target_name'])
+ return user_file
+
+
+def _GetMSVSConfigurationType(spec, build_file):
+ """Returns the configuration type for this project. It's a number defined
+ by Microsoft. May raise an exception.
+ Returns:
+ An integer, the configuration type.
+ """
+ try:
+ config_type = {
+ 'executable': '1', # .exe
+ 'shared_library': '2', # .dll
+ 'loadable_module': '2', # .dll
+ 'static_library': '4', # .lib
+ 'none': '10', # Utility type
+ 'dummy_executable': '1', # .exe
+ }[spec['type']]
+ except KeyError, e:
+ if spec.get('type'):
+ raise Exception('Target type %s is not a valid target type for '
+ 'target %s in %s.' %
+ (spec['type'], spec['target_name'], build_file))
+ else:
+ raise Exception('Missing type field for target %s in %s.' %
+ (spec['target_name'], build_file))
+ return config_type
+
+
+def _AddConfigurationToMSVSProject(p, spec, config_type, config_name, config):
+ """Many settings in a vcproj file are specific to a configuration. This
+ function the main part of the vcproj file that's configuration specific.
+
+ Arguments:
+ p: The target project being generated.
+ spec: The target dictionary containing the properties of the target.
+ config_type: The configuration type, a number as defined by Microsoft.
+ config_name: The name of the configuration.
+ config: The dictionnary that defines the special processing to be done
+ for this configuration.
+ """
+ # Get the information for this configuration
+ include_dirs, resource_include_dirs = _GetIncludeDirs(config)
+ libraries = _GetLibraries(config, spec)
+ out_file, vc_tool = _GetOutputFilePathAndTool(spec)
+ defines = _GetDefines(config)
+ defines = [_EscapeCppDefineForMSVS(d) for d in defines]
+ disabled_warnings = _GetDisabledWarnings(config)
+ prebuild = config.get('msvs_prebuild')
+ postbuild = config.get('msvs_postbuild')
+ def_file = _GetModuleDefinition(spec)
+ precompiled_header = config.get('msvs_precompiled_header')
+
+ # Prepare the list of tools as a dictionary.
+ tools = dict()
+ # Add in user specified msvs_settings.
+ msvs_settings = config.get('msvs_settings', {})
+ MSVSSettings.ValidateMSVSSettings(msvs_settings)
+ for tool in msvs_settings:
+ settings = config['msvs_settings'][tool]
+ for setting in settings:
+ _ToolAppend(tools, tool, setting, settings[setting])
+ # Add the information to the appropriate tool
+ _ToolAppend(tools, 'VCCLCompilerTool',
+ 'AdditionalIncludeDirectories', include_dirs)
+ _ToolAppend(tools, 'VCResourceCompilerTool',
+ 'AdditionalIncludeDirectories', resource_include_dirs)
+ # Add in libraries.
+ _ToolAppend(tools, 'VCLinkerTool', 'AdditionalDependencies', libraries)
+ if out_file:
+ _ToolAppend(tools, vc_tool, 'OutputFile', out_file, only_if_unset=True)
+ # Add defines.
+ _ToolAppend(tools, 'VCCLCompilerTool', 'PreprocessorDefinitions', defines)
+ _ToolAppend(tools, 'VCResourceCompilerTool', 'PreprocessorDefinitions',
+ defines)
+ # Change program database directory to prevent collisions.
+ _ToolAppend(tools, 'VCCLCompilerTool', 'ProgramDataBaseFileName',
+ '$(IntDir)\\$(ProjectName)\\vc80.pdb')
+ # Add disabled warnings.
+ _ToolAppend(tools, 'VCCLCompilerTool',
+ 'DisableSpecificWarnings', disabled_warnings)
+ # Add Pre-build.
+ _ToolAppend(tools, 'VCPreBuildEventTool', 'CommandLine', prebuild)
+ # Add Post-build.
+ _ToolAppend(tools, 'VCPostBuildEventTool', 'CommandLine', postbuild)
+ # Turn on precompiled headers if appropriate.
+ if precompiled_header:
+ precompiled_header = os.path.split(precompiled_header)[1]
+ _ToolAppend(tools, 'VCCLCompilerTool', 'UsePrecompiledHeader', '2')
+ _ToolAppend(tools, 'VCCLCompilerTool',
+ 'PrecompiledHeaderThrough', precompiled_header)
+ _ToolAppend(tools, 'VCCLCompilerTool',
+ 'ForcedIncludeFiles', precompiled_header)
+ # Loadable modules don't generate import libraries;
+ # tell dependent projects to not expect one.
+ if spec['type'] == 'loadable_module':
+ _ToolAppend(tools, 'VCLinkerTool', 'IgnoreImportLibrary', 'true')
+ # Set the module definition file if any.
+ if def_file:
+ _ToolAppend(tools, 'VCLinkerTool', 'ModuleDefinitionFile', def_file)
+
+ _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name)
+
+
+def _GetIncludeDirs(config):
+ """Returns the list of directories to be used for #include directives.
+
+ Arguments:
+ config: The dictionnary that defines the special processing to be done
+ for this configuration.
+ Returns:
+ The list of directory paths.
+ """
+ # TODO(bradnelson): include_dirs should really be flexible enough not to
+ # require this sort of thing.
+ include_dirs = (
+ config.get('include_dirs', []) +
+ config.get('msvs_system_include_dirs', []))
+ resource_include_dirs = config.get('resource_include_dirs', include_dirs)
+ include_dirs = [_FixPath(i) for i in include_dirs]
+ resource_include_dirs = [_FixPath(i) for i in resource_include_dirs]
+ return include_dirs, resource_include_dirs
+
+
+def _GetLibraries(config, spec):
+ """Returns the list of libraries for this configuration.
+
+ Arguments:
+ config: The dictionnary that defines the special processing to be done
+ for this configuration.
+ spec: The target dictionary containing the properties of the target.
+ Returns:
+ The list of directory paths.
+ """
+ libraries = spec.get('libraries', [])
+ # Strip out -l, as it is not used on windows (but is needed so we can pass
+ # in libraries that are assumed to be in the default library path).
+ return [re.sub('^(\-l)', '', lib) for lib in libraries]
+
+
+def _GetOutputFilePathAndTool(spec):
+ """Figures out the path of the file this spec will create and the name of
+ the VC tool that will create it.
+
+ Arguments:
+ spec: The target dictionary containing the properties of the target.
+ Returns:
+ A pair of (file path, name of the tool)
+ """
+ # Select a name for the output file.
+ out_file = ''
+ vc_tool = ''
+ output_file_map = {
+ 'executable': ('VCLinkerTool', '$(OutDir)\\', '.exe'),
+ 'shared_library': ('VCLinkerTool', '$(OutDir)\\', '.dll'),
+ 'loadable_module': ('VCLinkerTool', '$(OutDir)\\', '.dll'),
+ 'static_library': ('VCLibrarianTool', '$(OutDir)\\lib\\', '.lib'),
+ 'dummy_executable': ('VCLinkerTool', '$(IntDir)\\', '.junk'),
+ }
+ output_file_props = output_file_map.get(spec['type'])
+ if output_file_props and int(spec.get('msvs_auto_output_file', 1)):
+ vc_tool, out_dir, suffix = output_file_props
+ out_dir = spec.get('product_dir', out_dir)
+ product_extension = spec.get('product_extension')
+ if product_extension:
+ suffix = '.' + product_extension
+ prefix = spec.get('product_prefix', '')
+ product_name = spec.get('product_name', '$(ProjectName)')
+ out_file = ntpath.join(out_dir, prefix + product_name + suffix)
+ return out_file, vc_tool
+
+
+def _GetDefines(config):
+ """Returns the list of preprocessor definitions for this configuation.
+
+ Arguments:
+ config: The dictionnary that defines the special processing to be done
+ for this configuration.
+ Returns:
+ The list of preprocessor definitions.
+ """
+ defines = []
+ for d in config.get('defines', []):
+ if type(d) == list:
+ fd = '='.join([str(dpart) for dpart in d])
+ else:
+ fd = str(d)
+ defines.append(fd)
+ return defines
+
+
+def _GetDisabledWarnings(config):
+ return [str(i) for i in config.get('msvs_disabled_warnings', [])]
+
+
+def _GetModuleDefinition(spec):
+ def_file = ""
+ if spec['type'] in ['shared_library', 'loadable_module']:
+ def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
+ if len(def_files) == 1:
+ def_file = _FixPath(def_files[0])
+ elif def_files:
+ raise ValueError('Multiple module definition files in one target, '
+ 'target %s lists multiple .def files: %s' % (
+ spec['target_name'], ' '.join(def_files)))
+ return def_file
+
+
+def _ConvertToolsToExpectedForm(tools):
+ """ Convert the content of the tools array to a form expected by
+ VisualStudio.
+
+ Arguments:
+ tools: A dictionnary of settings; the tool name is the key.
+ Returns:
+ A list of Tool objects.
+ """
+ tool_list = []
+ for tool, settings in tools.iteritems():
+ # Collapse settings with lists.
+ settings_fixed = {}
+ for setting, value in settings.iteritems():
+ if type(value) == list:
+ if ((tool == 'VCLinkerTool' and
+ setting == 'AdditionalDependencies') or
+ setting == 'AdditionalOptions'):
+ settings_fixed[setting] = ' '.join(value)
+ else:
+ settings_fixed[setting] = ';'.join(value)
+ else:
+ settings_fixed[setting] = value
+ # Add in this tool.
+ tool_list.append(MSVSProject.Tool(tool, settings_fixed))
+ return tool_list
+
+
+def _AddConfigurationToMSVS(p, spec, tools, config, config_type, config_name):
+ """Add to the project file the configuration specified by config.
+
+ Arguments:
+ p: The target project being generated.
+ spec: the target project dict.
+ tools: A dictionnary of settings; the tool name is the key.
+ config: The dictionnary that defines the special processing to be done
+ for this configuration.
+ config_type: The configuration type, a number as defined by Microsoft.
+ config_name: The name of the configuration.
+ """
+ attributes = _GetMSVSAttributes(spec, config, config_type)
+ # Add in this configuration.
+ tool_list = _ConvertToolsToExpectedForm(tools)
+ p.AddConfig(_ConfigFullName(config_name, config),
+ attrs=attributes, tools=tool_list)
+
+def _GetMSVSAttributes(spec, config, config_type):
+ # Prepare configuration attributes.
+ prepared_attrs = {}
+ source_attrs = config.get('msvs_configuration_attributes', {})
+ for a in source_attrs:
+ prepared_attrs[a] = source_attrs[a]
+ # Add props files.
+ vsprops_dirs = config.get('msvs_props', [])
+ vsprops_dirs = [_FixPath(i) for i in vsprops_dirs]
+ if vsprops_dirs:
+ prepared_attrs['InheritedPropertySheets'] = ';'.join(vsprops_dirs)
+ # Set configuration type.
+ prepared_attrs['ConfigurationType'] = config_type
+ if not prepared_attrs.has_key('OutputDirectory'):
+ prepared_attrs['OutputDirectory'] = '$(SolutionDir)$(ConfigurationName)'
+ if not prepared_attrs.has_key('IntermediateDirectory'):
+ intermediate = '$(ConfigurationName)\\obj\\$(ProjectName)'
+ prepared_attrs['IntermediateDirectory'] = intermediate
+ return prepared_attrs
+
+def _AddNormalizedSources(sources_set, sources_array):
+ sources = [_NormalizedSource(s) for s in sources_array]
+ sources_set.update(set(sources))
+
+def _PrepareListOfSources(project, spec, relative_path_of_gyp_file):
+ """Prepare list of sources and excluded sources.
+
+ Besides the sources specified directly in the spec, adds the gyp file so
+ that a change to it will cause a re-compile. Also adds appropriate sources
+ for actions and copies. Assumes later stage will un-exclude files which
+ have custom build steps attached.
+
+ Arguments:
+ project: the MSVSProject object.
+ spec: The target dictionary containing the properties of the target.
+ relative_path_of_gyp_file: The relative path of the gyp file.
+ Returns:
+ A pair of (list of sources, list of excluded sources)
+ """
+ sources = set()
+ _AddNormalizedSources(sources, spec.get('sources', []))
+ excluded_sources = set()
+ # Add in the gyp file.
+ sources.add(relative_path_of_gyp_file)
+
+ # Add in 'action' inputs and outputs.
+ for a in spec.get('actions', []):
+ inputs = a.get('inputs', [])
+ inputs = [_NormalizedSource(i) for i in inputs]
+ # Add all inputs to sources and excluded sources.
+ inputs = set(inputs)
+ sources.update(inputs)
+ excluded_sources.update(inputs)
+ if int(a.get('process_outputs_as_sources', False)):
+ _AddNormalizedSources(sources, a.get('outputs', []))
+ # Add in 'copies' inputs and outputs.
+ for cpy in spec.get('copies', []):
+ _AddNormalizedSources(sources, cpy.get('files', []))
+ return (sources, excluded_sources)
+
+
+def _AdjustSourcesAndConvertToFilterHierarchy(
+ spec, options, gyp_dir, sources, excluded_sources):
+ """Adjusts the list of sources and excluded sources.
+ Also converts the sets to lists.
+
+ Arguments:
+ spec: The target dictionary containing the properties of the target.
+ options: Global generator options.
+ gyp_dir: The path to the gyp file being processed.
+ sources: A set of sources to be included for this project.
+ sources: A set of sources to be excluded for this project.
+ Returns:
+ A trio of (list of sources, list of excluded sources,
+ path of excluded IDL file)
+ """
+ # Exclude excluded sources coming into the generator.
+ excluded_sources.update(set(spec.get('sources_excluded', [])))
+ # Add excluded sources into sources for good measure.
+ sources.update(excluded_sources)
+ # Convert to proper windows form.
+ # NOTE: sources goes from being a set to a list here.
+ # NOTE: excluded_sources goes from being a set to a list here.
+ sources = [_FixPath(i) for i in sources]
+ # Convert to proper windows form.
+ excluded_sources = [_FixPath(i) for i in excluded_sources]
+
+ excluded_idl = _IdlFilesHandledNonNatively(spec, sources)
+
+ precompiled_related = _GetPrecompileRelatedFiles(spec)
+ # Find the excluded ones, minus the precompiled header related ones.
+ fully_excluded = [i for i in excluded_sources if i not in precompiled_related]
+
+ # Convert to folders and the right slashes.
+ sources = [i.split('\\') for i in sources]
+ sources = _ConvertSourcesToFilterHierarchy(sources, excluded=fully_excluded)
+ # Add in dummy file for type none.
+ if spec['type'] == 'dummy_executable':
+ # Pull in a dummy main so it can link successfully.
+ dummy_relpath = gyp.common.RelativePath(
+ options.depth + '\\tools\\gyp\\gyp_dummy.c', gyp_dir)
+ sources.append(dummy_relpath)
+
+ return sources, excluded_sources, excluded_idl
+
+
+def _IdlFilesHandledNonNatively(spec, sources):
+ # If any non-native rules use 'idl' as an extension exclude idl files.
+ # Gather a list here to use later.
+ using_idl = False
+ for rule in spec.get('rules', []):
+ if rule['extension'] == 'idl' and int(rule.get('msvs_external_rule', 0)):
+ using_idl = True
+ break
+ if using_idl:
+ excluded_idl = [i for i in sources if i.endswith('.idl')]
+ else:
+ excluded_idl = []
+ return excluded_idl
+
+
+def _GetPrecompileRelatedFiles(spec):
+ # Gather a list of precompiled header related sources.
+ precompiled_related = []
+ for config_name, config in spec['configurations'].iteritems():
+ for k in precomp_keys:
+ f = config.get(k)
+ if f:
+ precompiled_related.append(_FixPath(f))
+ return precompiled_related
+
+
+def _ExcludeFilesFromBeingBuilt(p, spec, excluded_sources, excluded_idl):
+ exclusions = _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl)
+ for file_name, excluded_configs in exclusions.iteritems():
+ for config_name, config in excluded_configs:
+ p.AddFileConfig(file_name, _ConfigFullName(config_name, config),
+ {'ExcludedFromBuild': 'true'})
+
+
+def _GetExcludedFilesFromBuild(spec, excluded_sources, excluded_idl):
+ exclusions = {}
+ # Exclude excluded sources from being built.
+ for f in excluded_sources:
+ excluded_configs = []
+ for config_name, config in spec['configurations'].iteritems():
+ precomped = [_FixPath(config.get(i, '')) for i in precomp_keys]
+ # Don't do this for ones that are precompiled header related.
+ if f not in precomped:
+ excluded_configs.append((config_name, config))
+ exclusions[f] = excluded_configs
+ # If any non-native rules use 'idl' as an extension exclude idl files.
+ # Exclude them now.
+ for f in excluded_idl:
+ excluded_configs = []
+ for config_name, config in spec['configurations'].iteritems():
+ excluded_configs.append((config_name, config))
+ exclusions[f] = excluded_configs
+ return exclusions
+
+def _AddToolFilesToMSVS(p, spec):
+ # Add in tool files (rules).
+ tool_files = set()
+ for config_name, config in spec['configurations'].iteritems():
+ for f in config.get('msvs_tool_files', []):
+ tool_files.add(f)
+ for f in tool_files:
+ p.AddToolFile(f)
+
+
+def _HandlePreCompileHeaderStubs(p, spec):
+ # Handle pre-compiled headers source stubs specially.
+ for config_name, config in spec['configurations'].iteritems():
+ source = config.get('msvs_precompiled_source')
+ if source:
+ source = _FixPath(source)
+ # UsePrecompiledHeader=1 for if using precompiled headers.
+ tool = MSVSProject.Tool('VCCLCompilerTool',
+ {'UsePrecompiledHeader': '1'})
+ p.AddFileConfig(source, _ConfigFullName(config_name, config),
+ {}, tools=[tool])
+
+
+def _AddActions(actions_to_add, spec, relative_path_of_gyp_file):
+ # Add actions.
+ actions = spec.get('actions', [])
+ for a in actions:
+ cmd = _BuildCommandLineForRule(spec, a, has_input_path=False)
+ # Attach actions to the gyp file if nothing else is there.
+ inputs = a.get('inputs') or [relative_path_of_gyp_file]
+ # Add the action.
+ _AddActionStep(actions_to_add,
+ inputs=inputs,
+ outputs=a.get('outputs', []),
+ description=a.get('message', a['action_name']),
+ command=cmd)
+
+
+def _WriteMSVSUserFile(project_path, version, spec):
+ # Add run_as and test targets.
+ if 'run_as' in spec:
+ run_as = spec['run_as']
+ action = run_as.get('action', [])
+ environment = run_as.get('environment', [])
+ working_directory = run_as.get('working_directory', '.')
+ elif int(spec.get('test', 0)):
+ action = ['$(TargetPath)', '--gtest_print_time']
+ environment = []
+ working_directory = '.'
+ else:
+ return # Nothing to add
+ # Write out the user file.
+ user_file = _CreateMSVSUserFile(project_path, version, spec)
+ for config_name, c_data in spec['configurations'].iteritems():
+ user_file.AddDebugSettings(_ConfigFullName(config_name, c_data),
+ action, environment, working_directory)
+ user_file.Write()
+
+
+def _AddCopies(actions_to_add, spec):
+ copies = _GetCopies(spec)
+ for inputs, outputs, cmd, description in copies:
+ _AddActionStep(actions_to_add, inputs=inputs, outputs=outputs,
+ description=description, command=cmd)
+
+
+def _GetCopies(spec):
+ copies = []
+ # Add copies.
+ for cpy in spec.get('copies', []):
+ for src in cpy.get('files', []):
+ dst = os.path.join(cpy['destination'], os.path.basename(src))
+ # _AddCustomBuildToolForMSVS() will call _FixPath() on the inputs and
+ # outputs, so do the same for our generated command line.
+ if src.endswith('/'):
+ src_bare = src[:-1]
+ base_dir = posixpath.split(src_bare)[0]
+ outer_dir = posixpath.split(src_bare)[1]
+ cmd = 'cd "%s" && xcopy /e /f /y "%s" "%s\\%s\\"' % (
+ _FixPath(base_dir), outer_dir, _FixPath(dst), outer_dir)
+ copies.append(([src], ['dummy_copies', dst], cmd,
+ 'Copying %s to %s' % (src, dst)))
+ else:
+ cmd = 'mkdir "%s" 2>nul & set ERRORLEVEL=0 & copy /Y "%s" "%s"' % (
+ _FixPath(cpy['destination']), _FixPath(src), _FixPath(dst))
+ copies.append(([src], [dst], cmd, 'Copying %s to %s' % (src, dst)))
+ return copies
+
+
+def _GetPathDict(root, path):
+ if path == '':
+ return root
+ parent, folder = os.path.split(path)
+ parent_dict = _GetPathDict(root, parent)
+ if folder not in parent_dict:
+ parent_dict[folder] = dict()
+ return parent_dict[folder]
+
+
+def _DictsToFolders(base_path, bucket, flat):
+ # Convert to folders recursively.
+ children = []
+ for folder, contents in bucket.iteritems():
+ if type(contents) == dict:
+ folder_children = _DictsToFolders(os.path.join(base_path, folder),
+ contents, flat)
+ if flat:
+ children += folder_children
+ else:
+ folder_children = MSVSNew.MSVSFolder(os.path.join(base_path, folder),
+ name='(' + folder + ')',
+ entries=folder_children)
+ children.append(folder_children)
+ else:
+ children.append(contents)
+ return children
+
+
+def _CollapseSingles(parent, node):
+ # Recursively explorer the tree of dicts looking for projects which are
+ # the sole item in a folder which has the same name as the project. Bring
+ # such projects up one level.
+ if (type(node) == dict and
+ len(node) == 1 and
+ node.keys()[0] == parent + '.vcproj'):
+ return node[node.keys()[0]]
+ if type(node) != dict:
+ return node
+ for child in node.keys():
+ node[child] = _CollapseSingles(child, node[child])
+ return node
+
+
+def _GatherSolutionFolders(sln_projects, project_objects, flat):
+ root = {}
+ # Convert into a tree of dicts on path.
+ for p in sln_projects:
+ gyp_file, target = gyp.common.ParseQualifiedTarget(p)[0:2]
+ gyp_dir = os.path.dirname(gyp_file)
+ path_dict = _GetPathDict(root, gyp_dir)
+ path_dict[target + '.vcproj'] = project_objects[p]
+ # Walk down from the top until we hit a folder that has more than one entry.
+ # In practice, this strips the top-level "src/" dir from the hierarchy in
+ # the solution.
+ while len(root) == 1 and type(root[root.keys()[0]]) == dict:
+ root = root[root.keys()[0]]
+ # Collapse singles.
+ root = _CollapseSingles('', root)
+ # Merge buckets until everything is a root entry.
+ return _DictsToFolders('', root, flat)
+
+
+def _GetPathOfProject(qualified_target, spec, options, msvs_version):
+ default_config = _GetDefaultConfiguration(spec)
+ proj_filename = default_config.get('msvs_existing_vcproj')
+ if not proj_filename:
+ proj_filename = (spec['target_name'] + options.suffix +
+ msvs_version.ProjectExtension())
+
+ build_file = gyp.common.BuildFile(qualified_target)
+ proj_path = os.path.join(os.path.split(build_file)[0], proj_filename)
+ fixpath_prefix = None
+ if options.generator_output:
+ projectDirPath = os.path.dirname(os.path.abspath(proj_path))
+ proj_path = os.path.join(options.generator_output, proj_path)
+ fixpath_prefix = gyp.common.RelativePath(projectDirPath,
+ os.path.dirname(proj_path))
+ return proj_path, fixpath_prefix
+
+
+def _GetPlatformOverridesOfProject(spec):
+ # Prepare a dict indicating which project configurations are used for which
+ # solution configurations for this target.
+ config_platform_overrides = {}
+ for config_name, c in spec['configurations'].iteritems():
+ config_fullname = _ConfigFullName(config_name, c)
+ platform = c.get('msvs_target_platform', _ConfigPlatform(c))
+ fixed_config_fullname = '%s|%s' % (
+ _ConfigBaseName(config_name, _ConfigPlatform(c)), platform)
+ config_platform_overrides[config_fullname] = fixed_config_fullname
+ return config_platform_overrides
+
+
+def _CreateProjectObjects(target_list, target_dicts, options, msvs_version):
+ """Create a MSVSProject object for the targets found in target list.
+
+ Arguments:
+ target_list: the list of targets to generate project objects for.
+ target_dicts: the dictionary of specifications.
+ options: global generator options.
+ version: the MSVSVersion object.
+ Returns:
+ A set of created projects, keyed by target.
+ """
+ global fixpath_prefix
+ # Generate each project.
+ projects = {}
+ for qualified_target in target_list:
+ spec = target_dicts[qualified_target]
+ if spec['toolset'] != 'target':
+ raise Exception(
+ 'Multiple toolsets not supported in msvs build (target %s)' %
+ qualified_target)
+ proj_path, fixpath_prefix = _GetPathOfProject(qualified_target, spec,
+ options, msvs_version)
+ guid = _GetGuidOfProject(proj_path, spec)
+ overrides = _GetPlatformOverridesOfProject(spec)
+ build_file = gyp.common.BuildFile(qualified_target)
+ # Create object for this project.
+ obj = MSVSNew.MSVSProject(
+ _FixPath(proj_path),
+ name=spec['target_name'],
+ guid=guid,
+ spec=spec,
+ build_file=build_file,
+ config_platform_overrides=overrides,
+ fixpath_prefix=fixpath_prefix)
+ projects[qualified_target] = obj
+ # Set all the dependencies
+ for project in projects.values():
+ deps = project.spec.get('dependencies', [])
+ deps = [projects[d] for d in deps]
+ project.set_dependencies(deps)
+ return projects
+
+
+def CalculateVariables(default_variables, params):
+ """Generated variables that require params to be known."""
+
+ generator_flags = params.get('generator_flags', {})
+
+ # Select project file format version (if unset, default to auto detecting).
+ msvs_version = \
+ MSVSVersion.SelectVisualStudioVersion(generator_flags.get('msvs_version',
+ 'auto'))
+ # Stash msvs_version for later (so we don't have to probe the system twice).
+ params['msvs_version'] = msvs_version
+
+ # Set a variable so conditions can be based on msvs_version.
+ default_variables['MSVS_VERSION'] = msvs_version.ShortName()
+
+ # To determine processor word size on Windows, in addition to checking
+ # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
+ # process), it is also necessary to check PROCESSOR_ARCITEW6432 (which
+ # contains the actual word size of the system when running thru WOW64).
+ if (os.environ.get('PROCESSOR_ARCHITECTURE', '').find('64') >= 0 or
+ os.environ.get('PROCESSOR_ARCHITEW6432', '').find('64') >= 0):
+ default_variables['MSVS_OS_BITS'] = 64
+ else:
+ default_variables['MSVS_OS_BITS'] = 32
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ """Generate .sln and .vcproj files.
+
+ This is the entry point for this generator.
+ Arguments:
+ target_list: List of target pairs: 'base/base.gyp:base'.
+ target_dicts: Dict of target properties keyed on target pair.
+ data: Dictionary containing per .gyp data.
+ """
+ global fixpath_prefix
+
+ options = params['options']
+ generator_flags = params.get('generator_flags', {})
+
+ # Get the project file format version back out of where we stashed it in
+ # GeneratorCalculatedVariables.
+ msvs_version = params['msvs_version']
+
+ # Prepare the set of configurations.
+ configs = set()
+ for qualified_target in target_list:
+ spec = target_dicts[qualified_target]
+ for config_name, config in spec['configurations'].iteritems():
+ configs.add(_ConfigFullName(config_name, config))
+ configs = list(configs)
+
+ # Figure out all the projects that will be generated and their guids
+ project_objects = _CreateProjectObjects(target_list, target_dicts, options,
+ msvs_version)
+
+ # Generate each project.
+ for project in project_objects.values():
+ fixpath_prefix = project.fixpath_prefix
+ _GenerateProject(project, options, msvs_version)
+ fixpath_prefix = None
+
+ for build_file in data.keys():
+ # Validate build_file extension
+ if build_file[-4:] != '.gyp':
+ continue
+ sln_path = build_file[:-4] + options.suffix + '.sln'
+ if options.generator_output:
+ sln_path = os.path.join(options.generator_output, sln_path)
+ # Get projects in the solution, and their dependents.
+ sln_projects = gyp.common.BuildFileTargets(target_list, build_file)
+ sln_projects += gyp.common.DeepDependencyTargets(target_dicts, sln_projects)
+ # Create folder hierarchy.
+ root_entries = _GatherSolutionFolders(
+ sln_projects, project_objects, flat=msvs_version.FlatSolution())
+ # Create solution.
+ sln = MSVSNew.MSVSSolution(sln_path,
+ entries=root_entries,
+ variants=configs,
+ websiteProperties=False,
+ version=msvs_version)
+ sln.Write()
diff --git a/Source/ThirdParty/gyp/pylib/gyp/generator/scons.py b/Source/ThirdParty/gyp/pylib/gyp/generator/scons.py
new file mode 100644
index 000000000..073f9e047
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/generator/scons.py
@@ -0,0 +1,1045 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import gyp
+import gyp.common
+import gyp.SCons as SCons
+import os.path
+import pprint
+import re
+
+
+# TODO: remove when we delete the last WriteList() call in this module
+WriteList = SCons.WriteList
+
+
+generator_default_variables = {
+ 'EXECUTABLE_PREFIX': '',
+ 'EXECUTABLE_SUFFIX': '',
+ 'STATIC_LIB_PREFIX': '${LIBPREFIX}',
+ 'SHARED_LIB_PREFIX': '${SHLIBPREFIX}',
+ 'STATIC_LIB_SUFFIX': '${LIBSUFFIX}',
+ 'SHARED_LIB_SUFFIX': '${SHLIBSUFFIX}',
+ 'INTERMEDIATE_DIR': '${INTERMEDIATE_DIR}',
+ 'SHARED_INTERMEDIATE_DIR': '${SHARED_INTERMEDIATE_DIR}',
+ 'OS': 'linux',
+ 'PRODUCT_DIR': '$TOP_BUILDDIR',
+ 'SHARED_LIB_DIR': '$LIB_DIR',
+ 'LIB_DIR': '$LIB_DIR',
+ 'RULE_INPUT_ROOT': '${SOURCE.filebase}',
+ 'RULE_INPUT_EXT': '${SOURCE.suffix}',
+ 'RULE_INPUT_NAME': '${SOURCE.file}',
+ 'RULE_INPUT_PATH': '${SOURCE.abspath}',
+ 'CONFIGURATION_NAME': '${CONFIG_NAME}',
+}
+
+# Tell GYP how to process the input for us.
+generator_handles_variants = True
+generator_wants_absolute_build_file_paths = True
+
+
+def FixPath(path, prefix):
+ if not os.path.isabs(path) and not path[0] == '$':
+ path = prefix + path
+ return path
+
+
+header = """\
+# This file is generated; do not edit.
+"""
+
+
+_alias_template = """
+if GetOption('verbose'):
+ _action = Action([%(action)s])
+else:
+ _action = Action([%(action)s], %(message)s)
+_outputs = env.Alias(
+ ['_%(target_name)s_action'],
+ %(inputs)s,
+ _action
+)
+env.AlwaysBuild(_outputs)
+"""
+
+_run_as_template = """
+if GetOption('verbose'):
+ _action = Action([%(action)s])
+else:
+ _action = Action([%(action)s], %(message)s)
+"""
+
+_run_as_template_suffix = """
+_run_as_target = env.Alias('run_%(target_name)s', target_files, _action)
+env.Requires(_run_as_target, [
+ Alias('%(target_name)s'),
+])
+env.AlwaysBuild(_run_as_target)
+"""
+
+_command_template = """
+if GetOption('verbose'):
+ _action = Action([%(action)s])
+else:
+ _action = Action([%(action)s], %(message)s)
+_outputs = env.Command(
+ %(outputs)s,
+ %(inputs)s,
+ _action
+)
+"""
+
+# This is copied from the default SCons action, updated to handle symlinks.
+_copy_action_template = """
+import shutil
+import SCons.Action
+
+def _copy_files_or_dirs_or_symlinks(dest, src):
+ SCons.Node.FS.invalidate_node_memos(dest)
+ if SCons.Util.is_List(src) and os.path.isdir(dest):
+ for file in src:
+ shutil.copy2(file, dest)
+ return 0
+ elif os.path.islink(src):
+ linkto = os.readlink(src)
+ os.symlink(linkto, dest)
+ return 0
+ elif os.path.isfile(src):
+ return shutil.copy2(src, dest)
+ else:
+ return shutil.copytree(src, dest, 1)
+
+def _copy_files_or_dirs_or_symlinks_str(dest, src):
+ return 'Copying %s to %s ...' % (src, dest)
+
+GYPCopy = SCons.Action.ActionFactory(_copy_files_or_dirs_or_symlinks,
+ _copy_files_or_dirs_or_symlinks_str,
+ convert=str)
+"""
+
+_rule_template = """
+%(name)s_additional_inputs = %(inputs)s
+%(name)s_outputs = %(outputs)s
+def %(name)s_emitter(target, source, env):
+ return (%(name)s_outputs, source + %(name)s_additional_inputs)
+if GetOption('verbose'):
+ %(name)s_action = Action([%(action)s])
+else:
+ %(name)s_action = Action([%(action)s], %(message)s)
+env['BUILDERS']['%(name)s'] = Builder(action=%(name)s_action,
+ emitter=%(name)s_emitter)
+
+_outputs = []
+_processed_input_files = []
+for infile in input_files:
+ if (type(infile) == type('')
+ and not os.path.isabs(infile)
+ and not infile[0] == '$'):
+ infile = %(src_dir)r + infile
+ if str(infile).endswith('.%(extension)s'):
+ _generated = env.%(name)s(infile)
+ env.Precious(_generated)
+ _outputs.append(_generated)
+ %(process_outputs_as_sources_line)s
+ else:
+ _processed_input_files.append(infile)
+prerequisites.extend(_outputs)
+input_files = _processed_input_files
+"""
+
+_spawn_hack = """
+import re
+import SCons.Platform.posix
+needs_shell = re.compile('["\\'><!^&]')
+def gyp_spawn(sh, escape, cmd, args, env):
+ def strip_scons_quotes(arg):
+ if arg[0] == '"' and arg[-1] == '"':
+ return arg[1:-1]
+ return arg
+ stripped_args = [strip_scons_quotes(a) for a in args]
+ if needs_shell.search(' '.join(stripped_args)):
+ return SCons.Platform.posix.exec_spawnvpe([sh, '-c', ' '.join(args)], env)
+ else:
+ return SCons.Platform.posix.exec_spawnvpe(stripped_args, env)
+"""
+
+
+def EscapeShellArgument(s):
+ """Quotes an argument so that it will be interpreted literally by a POSIX
+ shell. Taken from
+ http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python
+ """
+ return "'" + s.replace("'", "'\\''") + "'"
+
+
+def InvertNaiveSConsQuoting(s):
+ """SCons tries to "help" with quoting by naively putting double-quotes around
+ command-line arguments containing space or tab, which is broken for all
+ but trivial cases, so we undo it. (See quote_spaces() in Subst.py)"""
+ if ' ' in s or '\t' in s:
+ # Then SCons will put double-quotes around this, so add our own quotes
+ # to close its quotes at the beginning and end.
+ s = '"' + s + '"'
+ return s
+
+
+def EscapeSConsVariableExpansion(s):
+ """SCons has its own variable expansion syntax using $. We must escape it for
+ strings to be interpreted literally. For some reason this requires four
+ dollar signs, not two, even without the shell involved."""
+ return s.replace('$', '$$$$')
+
+
+def EscapeCppDefine(s):
+ """Escapes a CPP define so that it will reach the compiler unaltered."""
+ s = EscapeShellArgument(s)
+ s = InvertNaiveSConsQuoting(s)
+ s = EscapeSConsVariableExpansion(s)
+ return s
+
+
+def GenerateConfig(fp, config, indent='', src_dir=''):
+ """
+ Generates SCons dictionary items for a gyp configuration.
+
+ This provides the main translation between the (lower-case) gyp settings
+ keywords and the (upper-case) SCons construction variables.
+ """
+ var_mapping = {
+ 'ASFLAGS' : 'asflags',
+ 'CCFLAGS' : 'cflags',
+ 'CFLAGS' : 'cflags_c',
+ 'CXXFLAGS' : 'cflags_cc',
+ 'CPPDEFINES' : 'defines',
+ 'CPPPATH' : 'include_dirs',
+ # Add the ldflags value to $LINKFLAGS, but not $SHLINKFLAGS.
+ # SCons defines $SHLINKFLAGS to incorporate $LINKFLAGS, so
+ # listing both here would case 'ldflags' to get appended to
+ # both, and then have it show up twice on the command line.
+ 'LINKFLAGS' : 'ldflags',
+ }
+ postamble='\n%s],\n' % indent
+ for scons_var in sorted(var_mapping.keys()):
+ gyp_var = var_mapping[scons_var]
+ value = config.get(gyp_var)
+ if value:
+ if gyp_var in ('defines',):
+ value = [EscapeCppDefine(v) for v in value]
+ if gyp_var in ('include_dirs',):
+ if src_dir and not src_dir.endswith('/'):
+ src_dir += '/'
+ result = []
+ for v in value:
+ v = FixPath(v, src_dir)
+ # Force SCons to evaluate the CPPPATH directories at
+ # SConscript-read time, so delayed evaluation of $SRC_DIR
+ # doesn't point it to the --generator-output= directory.
+ result.append('env.Dir(%r)' % v)
+ value = result
+ else:
+ value = map(repr, value)
+ WriteList(fp,
+ value,
+ prefix=indent,
+ preamble='%s%s = [\n ' % (indent, scons_var),
+ postamble=postamble)
+
+
+def GenerateSConscript(output_filename, spec, build_file, build_file_data):
+ """
+ Generates a SConscript file for a specific target.
+
+ This generates a SConscript file suitable for building any or all of
+ the target's configurations.
+
+ A SConscript file may be called multiple times to generate targets for
+ multiple configurations. Consequently, it needs to be ready to build
+ the target for any requested configuration, and therefore contains
+ information about the settings for all configurations (generated into
+ the SConscript file at gyp configuration time) as well as logic for
+ selecting (at SCons build time) the specific configuration being built.
+
+ The general outline of a generated SConscript file is:
+
+ -- Header
+
+ -- Import 'env'. This contains a $CONFIG_NAME construction
+ variable that specifies what configuration to build
+ (e.g. Debug, Release).
+
+ -- Configurations. This is a dictionary with settings for
+ the different configurations (Debug, Release) under which this
+ target can be built. The values in the dictionary are themselves
+ dictionaries specifying what construction variables should added
+ to the local copy of the imported construction environment
+ (Append), should be removed (FilterOut), and should outright
+ replace the imported values (Replace).
+
+ -- Clone the imported construction environment and update
+ with the proper configuration settings.
+
+ -- Initialize the lists of the targets' input files and prerequisites.
+
+ -- Target-specific actions and rules. These come after the
+ input file and prerequisite initializations because the
+ outputs of the actions and rules may affect the input file
+ list (process_outputs_as_sources) and get added to the list of
+ prerequisites (so that they're guaranteed to be executed before
+ building the target).
+
+ -- Call the Builder for the target itself.
+
+ -- Arrange for any copies to be made into installation directories.
+
+ -- Set up the {name} Alias (phony Node) for the target as the
+ primary handle for building all of the target's pieces.
+
+ -- Use env.Require() to make sure the prerequisites (explicitly
+ specified, but also including the actions and rules) are built
+ before the target itself.
+
+ -- Return the {name} Alias to the calling SConstruct file
+ so it can be added to the list of default targets.
+ """
+ scons_target = SCons.Target(spec)
+
+ gyp_dir = os.path.dirname(output_filename)
+ if not gyp_dir:
+ gyp_dir = '.'
+ gyp_dir = os.path.abspath(gyp_dir)
+
+ output_dir = os.path.dirname(output_filename)
+ src_dir = build_file_data['_DEPTH']
+ src_dir_rel = gyp.common.RelativePath(src_dir, output_dir)
+ subdir = gyp.common.RelativePath(os.path.dirname(build_file), src_dir)
+ src_subdir = '$SRC_DIR/' + subdir
+ src_subdir_ = src_subdir + '/'
+
+ component_name = os.path.splitext(os.path.basename(build_file))[0]
+ target_name = spec['target_name']
+
+ if not os.path.exists(gyp_dir):
+ os.makedirs(gyp_dir)
+ fp = open(output_filename, 'w')
+ fp.write(header)
+
+ fp.write('\nimport os\n')
+ fp.write('\nImport("env")\n')
+
+ #
+ fp.write('\n')
+ fp.write('env = env.Clone(COMPONENT_NAME=%s,\n' % repr(component_name))
+ fp.write(' TARGET_NAME=%s)\n' % repr(target_name))
+
+ #
+ for config in spec['configurations'].itervalues():
+ if config.get('scons_line_length'):
+ fp.write(_spawn_hack)
+ break
+
+ #
+ indent = ' ' * 12
+ fp.write('\n')
+ fp.write('configurations = {\n')
+ for config_name, config in spec['configurations'].iteritems():
+ fp.write(' \'%s\' : {\n' % config_name)
+
+ fp.write(' \'Append\' : dict(\n')
+ GenerateConfig(fp, config, indent, src_subdir)
+ libraries = spec.get('libraries')
+ if libraries:
+ WriteList(fp,
+ map(repr, libraries),
+ prefix=indent,
+ preamble='%sLIBS = [\n ' % indent,
+ postamble='\n%s],\n' % indent)
+ fp.write(' ),\n')
+
+ fp.write(' \'FilterOut\' : dict(\n' )
+ for key, var in config.get('scons_remove', {}).iteritems():
+ fp.write(' %s = %s,\n' % (key, repr(var)))
+ fp.write(' ),\n')
+
+ fp.write(' \'Replace\' : dict(\n' )
+ scons_settings = config.get('scons_variable_settings', {})
+ for key in sorted(scons_settings.keys()):
+ val = pprint.pformat(scons_settings[key])
+ fp.write(' %s = %s,\n' % (key, val))
+ if 'c++' in spec.get('link_languages', []):
+ fp.write(' %s = %s,\n' % ('LINK', repr('$CXX')))
+ if config.get('scons_line_length'):
+ fp.write(' SPAWN = gyp_spawn,\n')
+ fp.write(' ),\n')
+
+ fp.write(' \'ImportExternal\' : [\n' )
+ for var in config.get('scons_import_variables', []):
+ fp.write(' %s,\n' % repr(var))
+ fp.write(' ],\n')
+
+ fp.write(' \'PropagateExternal\' : [\n' )
+ for var in config.get('scons_propagate_variables', []):
+ fp.write(' %s,\n' % repr(var))
+ fp.write(' ],\n')
+
+ fp.write(' },\n')
+ fp.write('}\n')
+
+ fp.write('\n'
+ 'config = configurations[env[\'CONFIG_NAME\']]\n'
+ 'env.Append(**config[\'Append\'])\n'
+ 'env.FilterOut(**config[\'FilterOut\'])\n'
+ 'env.Replace(**config[\'Replace\'])\n')
+
+ fp.write('\n'
+ '# Scons forces -fPIC for SHCCFLAGS on some platforms.\n'
+ '# Disable that so we can control it from cflags in gyp.\n'
+ '# Note that Scons itself is inconsistent with its -fPIC\n'
+ '# setting. SHCCFLAGS forces -fPIC, and SHCFLAGS does not.\n'
+ '# This will make SHCCFLAGS consistent with SHCFLAGS.\n'
+ 'env[\'SHCCFLAGS\'] = [\'$CCFLAGS\']\n')
+
+ fp.write('\n'
+ 'for _var in config[\'ImportExternal\']:\n'
+ ' if _var in ARGUMENTS:\n'
+ ' env[_var] = ARGUMENTS[_var]\n'
+ ' elif _var in os.environ:\n'
+ ' env[_var] = os.environ[_var]\n'
+ 'for _var in config[\'PropagateExternal\']:\n'
+ ' if _var in ARGUMENTS:\n'
+ ' env[_var] = ARGUMENTS[_var]\n'
+ ' elif _var in os.environ:\n'
+ ' env[\'ENV\'][_var] = os.environ[_var]\n')
+
+ fp.write('\n'
+ "env['ENV']['LD_LIBRARY_PATH'] = env.subst('$LIB_DIR')\n")
+
+ #
+ #fp.write("\nif env.has_key('CPPPATH'):\n")
+ #fp.write(" env['CPPPATH'] = map(env.Dir, env['CPPPATH'])\n")
+
+ variants = spec.get('variants', {})
+ for setting in sorted(variants.keys()):
+ if_fmt = 'if ARGUMENTS.get(%s) not in (None, \'0\'):\n'
+ fp.write('\n')
+ fp.write(if_fmt % repr(setting.upper()))
+ fp.write(' env.AppendUnique(\n')
+ GenerateConfig(fp, variants[setting], indent, src_subdir)
+ fp.write(' )\n')
+
+ #
+ scons_target.write_input_files(fp)
+
+ fp.write('\n')
+ fp.write('target_files = []\n')
+ prerequisites = spec.get('scons_prerequisites', [])
+ fp.write('prerequisites = %s\n' % pprint.pformat(prerequisites))
+
+ actions = spec.get('actions', [])
+ for action in actions:
+ a = ['cd', src_subdir, '&&'] + action['action']
+ message = action.get('message')
+ if message:
+ message = repr(message)
+ inputs = [FixPath(f, src_subdir_) for f in action.get('inputs', [])]
+ outputs = [FixPath(f, src_subdir_) for f in action.get('outputs', [])]
+ if outputs:
+ template = _command_template
+ else:
+ template = _alias_template
+ fp.write(template % {
+ 'inputs' : pprint.pformat(inputs),
+ 'outputs' : pprint.pformat(outputs),
+ 'action' : pprint.pformat(a),
+ 'message' : message,
+ 'target_name': target_name,
+ })
+ if int(action.get('process_outputs_as_sources', 0)):
+ fp.write('input_files.extend(_outputs)\n')
+ fp.write('prerequisites.extend(_outputs)\n')
+ fp.write('target_files.extend(_outputs)\n')
+
+ rules = spec.get('rules', [])
+ for rule in rules:
+ name = rule['rule_name']
+ a = ['cd', src_subdir, '&&'] + rule['action']
+ message = rule.get('message')
+ if message:
+ message = repr(message)
+ if int(rule.get('process_outputs_as_sources', 0)):
+ poas_line = '_processed_input_files.extend(_generated)'
+ else:
+ poas_line = '_processed_input_files.append(infile)'
+ inputs = [FixPath(f, src_subdir_) for f in rule.get('inputs', [])]
+ outputs = [FixPath(f, src_subdir_) for f in rule.get('outputs', [])]
+ fp.write(_rule_template % {
+ 'inputs' : pprint.pformat(inputs),
+ 'outputs' : pprint.pformat(outputs),
+ 'action' : pprint.pformat(a),
+ 'extension' : rule['extension'],
+ 'name' : name,
+ 'message' : message,
+ 'process_outputs_as_sources_line' : poas_line,
+ 'src_dir' : src_subdir_,
+ })
+
+ scons_target.write_target(fp, src_subdir)
+
+ copies = spec.get('copies', [])
+ if copies:
+ fp.write(_copy_action_template)
+ for copy in copies:
+ destdir = None
+ files = None
+ try:
+ destdir = copy['destination']
+ except KeyError, e:
+ gyp.common.ExceptionAppend(
+ e,
+ "Required 'destination' key missing for 'copies' in %s." % build_file)
+ raise
+ try:
+ files = copy['files']
+ except KeyError, e:
+ gyp.common.ExceptionAppend(
+ e, "Required 'files' key missing for 'copies' in %s." % build_file)
+ raise
+ if not files:
+ # TODO: should probably add a (suppressible) warning;
+ # a null file list may be unintentional.
+ continue
+ if not destdir:
+ raise Exception(
+ "Required 'destination' key is empty for 'copies' in %s." % build_file)
+
+ fmt = ('\n'
+ '_outputs = env.Command(%s,\n'
+ ' %s,\n'
+ ' GYPCopy(\'$TARGET\', \'$SOURCE\'))\n')
+ for f in copy['files']:
+ # Remove trailing separators so basename() acts like Unix basename and
+ # always returns the last element, whether a file or dir. Without this,
+ # only the contents, not the directory itself, are copied (and nothing
+ # might be copied if dest already exists, since scons thinks nothing needs
+ # to be done).
+ dest = os.path.join(destdir, os.path.basename(f.rstrip(os.sep)))
+ f = FixPath(f, src_subdir_)
+ dest = FixPath(dest, src_subdir_)
+ fp.write(fmt % (repr(dest), repr(f)))
+ fp.write('target_files.extend(_outputs)\n')
+
+ run_as = spec.get('run_as')
+ if run_as:
+ action = run_as.get('action', [])
+ working_directory = run_as.get('working_directory')
+ if not working_directory:
+ working_directory = gyp_dir
+ else:
+ if not os.path.isabs(working_directory):
+ working_directory = os.path.normpath(os.path.join(gyp_dir,
+ working_directory))
+ if run_as.get('environment'):
+ for (key, val) in run_as.get('environment').iteritems():
+ action = ['%s="%s"' % (key, val)] + action
+ action = ['cd', '"%s"' % working_directory, '&&'] + action
+ fp.write(_run_as_template % {
+ 'action' : pprint.pformat(action),
+ 'message' : run_as.get('message', ''),
+ })
+
+ fmt = "\ngyp_target = env.Alias('%s', target_files)\n"
+ fp.write(fmt % target_name)
+
+ dependencies = spec.get('scons_dependencies', [])
+ if dependencies:
+ WriteList(fp, dependencies, preamble='dependencies = [\n ',
+ postamble='\n]\n')
+ fp.write('env.Requires(target_files, dependencies)\n')
+ fp.write('env.Requires(gyp_target, dependencies)\n')
+ fp.write('for prerequisite in prerequisites:\n')
+ fp.write(' env.Requires(prerequisite, dependencies)\n')
+ fp.write('env.Requires(gyp_target, prerequisites)\n')
+
+ if run_as:
+ fp.write(_run_as_template_suffix % {
+ 'target_name': target_name,
+ })
+
+ fp.write('Return("gyp_target")\n')
+
+ fp.close()
+
+
+#############################################################################
+# TEMPLATE BEGIN
+
+_wrapper_template = """\
+
+__doc__ = '''
+Wrapper configuration for building this entire "solution,"
+including all the specific targets in various *.scons files.
+'''
+
+import os
+import sys
+
+import SCons.Environment
+import SCons.Util
+
+def GetProcessorCount():
+ '''
+ Detects the number of CPUs on the system. Adapted form:
+ http://codeliberates.blogspot.com/2008/05/detecting-cpuscores-in-python.html
+ '''
+ # Linux, Unix and Mac OS X:
+ if hasattr(os, 'sysconf'):
+ if os.sysconf_names.has_key('SC_NPROCESSORS_ONLN'):
+ # Linux and Unix or Mac OS X with python >= 2.5:
+ return os.sysconf('SC_NPROCESSORS_ONLN')
+ else: # Mac OS X with Python < 2.5:
+ return int(os.popen2("sysctl -n hw.ncpu")[1].read())
+ # Windows:
+ if os.environ.has_key('NUMBER_OF_PROCESSORS'):
+ return max(int(os.environ.get('NUMBER_OF_PROCESSORS', '1')), 1)
+ return 1 # Default
+
+# Support PROGRESS= to show progress in different ways.
+p = ARGUMENTS.get('PROGRESS')
+if p == 'spinner':
+ Progress(['/\\r', '|\\r', '\\\\\\r', '-\\r'],
+ interval=5,
+ file=open('/dev/tty', 'w'))
+elif p == 'name':
+ Progress('$TARGET\\r', overwrite=True, file=open('/dev/tty', 'w'))
+
+# Set the default -j value based on the number of processors.
+SetOption('num_jobs', GetProcessorCount() + 1)
+
+# Have SCons use its cached dependency information.
+SetOption('implicit_cache', 1)
+
+# Only re-calculate MD5 checksums if a timestamp has changed.
+Decider('MD5-timestamp')
+
+# Since we set the -j value by default, suppress SCons warnings about being
+# unable to support parallel build on versions of Python with no threading.
+default_warnings = ['no-no-parallel-support']
+SetOption('warn', default_warnings + GetOption('warn'))
+
+AddOption('--mode', nargs=1, dest='conf_list', default=[],
+ action='append', help='Configuration to build.')
+
+AddOption('--verbose', dest='verbose', default=False,
+ action='store_true', help='Verbose command-line output.')
+
+
+#
+sconscript_file_map = %(sconscript_files)s
+
+class LoadTarget:
+ '''
+ Class for deciding if a given target sconscript is to be included
+ based on a list of included target names, optionally prefixed with '-'
+ to exclude a target name.
+ '''
+ def __init__(self, load):
+ '''
+ Initialize a class with a list of names for possible loading.
+
+ Arguments:
+ load: list of elements in the LOAD= specification
+ '''
+ self.included = set([c for c in load if not c.startswith('-')])
+ self.excluded = set([c[1:] for c in load if c.startswith('-')])
+
+ if not self.included:
+ self.included = set(['all'])
+
+ def __call__(self, target):
+ '''
+ Returns True if the specified target's sconscript file should be
+ loaded, based on the initialized included and excluded lists.
+ '''
+ return (target in self.included or
+ ('all' in self.included and not target in self.excluded))
+
+if 'LOAD' in ARGUMENTS:
+ load = ARGUMENTS['LOAD'].split(',')
+else:
+ load = []
+load_target = LoadTarget(load)
+
+sconscript_files = []
+for target, sconscript in sconscript_file_map.iteritems():
+ if load_target(target):
+ sconscript_files.append(sconscript)
+
+
+target_alias_list= []
+
+conf_list = GetOption('conf_list')
+if conf_list:
+ # In case the same --mode= value was specified multiple times.
+ conf_list = list(set(conf_list))
+else:
+ conf_list = [%(default_configuration)r]
+
+sconsbuild_dir = Dir(%(sconsbuild_dir)s)
+
+
+def FilterOut(self, **kw):
+ kw = SCons.Environment.copy_non_reserved_keywords(kw)
+ for key, val in kw.items():
+ envval = self.get(key, None)
+ if envval is None:
+ # No existing variable in the environment, so nothing to delete.
+ continue
+
+ for vremove in val:
+ # Use while not if, so we can handle duplicates.
+ while vremove in envval:
+ envval.remove(vremove)
+
+ self[key] = envval
+
+ # TODO(sgk): SCons.Environment.Append() has much more logic to deal
+ # with various types of values. We should handle all those cases in here
+ # too. (If variable is a dict, etc.)
+
+
+non_compilable_suffixes = {
+ 'LINUX' : set([
+ '.bdic',
+ '.css',
+ '.dat',
+ '.fragment',
+ '.gperf',
+ '.h',
+ '.hh',
+ '.hpp',
+ '.html',
+ '.hxx',
+ '.idl',
+ '.in',
+ '.in0',
+ '.in1',
+ '.js',
+ '.mk',
+ '.rc',
+ '.sigs',
+ '',
+ ]),
+ 'WINDOWS' : set([
+ '.h',
+ '.hh',
+ '.hpp',
+ '.dat',
+ '.idl',
+ '.in',
+ '.in0',
+ '.in1',
+ ]),
+}
+
+def compilable(env, file):
+ base, ext = os.path.splitext(str(file))
+ if ext in non_compilable_suffixes[env['TARGET_PLATFORM']]:
+ return False
+ return True
+
+def compilable_files(env, sources):
+ return [x for x in sources if compilable(env, x)]
+
+def GypProgram(env, target, source, *args, **kw):
+ source = compilable_files(env, source)
+ result = env.Program(target, source, *args, **kw)
+ if env.get('INCREMENTAL'):
+ env.Precious(result)
+ return result
+
+def GypTestProgram(env, target, source, *args, **kw):
+ source = compilable_files(env, source)
+ result = env.Program(target, source, *args, **kw)
+ if env.get('INCREMENTAL'):
+ env.Precious(*result)
+ return result
+
+def GypLibrary(env, target, source, *args, **kw):
+ source = compilable_files(env, source)
+ result = env.Library(target, source, *args, **kw)
+ return result
+
+def GypLoadableModule(env, target, source, *args, **kw):
+ source = compilable_files(env, source)
+ result = env.LoadableModule(target, source, *args, **kw)
+ return result
+
+def GypStaticLibrary(env, target, source, *args, **kw):
+ source = compilable_files(env, source)
+ result = env.StaticLibrary(target, source, *args, **kw)
+ return result
+
+def GypSharedLibrary(env, target, source, *args, **kw):
+ source = compilable_files(env, source)
+ result = env.SharedLibrary(target, source, *args, **kw)
+ if env.get('INCREMENTAL'):
+ env.Precious(result)
+ return result
+
+def add_gyp_methods(env):
+ env.AddMethod(GypProgram)
+ env.AddMethod(GypTestProgram)
+ env.AddMethod(GypLibrary)
+ env.AddMethod(GypLoadableModule)
+ env.AddMethod(GypStaticLibrary)
+ env.AddMethod(GypSharedLibrary)
+
+ env.AddMethod(FilterOut)
+
+ env.AddMethod(compilable)
+
+
+base_env = Environment(
+ tools = %(scons_tools)s,
+ INTERMEDIATE_DIR='$OBJ_DIR/${COMPONENT_NAME}/_${TARGET_NAME}_intermediate',
+ LIB_DIR='$TOP_BUILDDIR/lib',
+ OBJ_DIR='$TOP_BUILDDIR/obj',
+ SCONSBUILD_DIR=sconsbuild_dir.abspath,
+ SHARED_INTERMEDIATE_DIR='$OBJ_DIR/_global_intermediate',
+ SRC_DIR=Dir(%(src_dir)r),
+ TARGET_PLATFORM='LINUX',
+ TOP_BUILDDIR='$SCONSBUILD_DIR/$CONFIG_NAME',
+ LIBPATH=['$LIB_DIR'],
+)
+
+if not GetOption('verbose'):
+ base_env.SetDefault(
+ ARCOMSTR='Creating library $TARGET',
+ ASCOMSTR='Assembling $TARGET',
+ CCCOMSTR='Compiling $TARGET',
+ CONCATSOURCECOMSTR='ConcatSource $TARGET',
+ CXXCOMSTR='Compiling $TARGET',
+ LDMODULECOMSTR='Building loadable module $TARGET',
+ LINKCOMSTR='Linking $TARGET',
+ MANIFESTCOMSTR='Updating manifest for $TARGET',
+ MIDLCOMSTR='Compiling IDL $TARGET',
+ PCHCOMSTR='Precompiling $TARGET',
+ RANLIBCOMSTR='Indexing $TARGET',
+ RCCOMSTR='Compiling resource $TARGET',
+ SHCCCOMSTR='Compiling $TARGET',
+ SHCXXCOMSTR='Compiling $TARGET',
+ SHLINKCOMSTR='Linking $TARGET',
+ SHMANIFESTCOMSTR='Updating manifest for $TARGET',
+ )
+
+add_gyp_methods(base_env)
+
+for conf in conf_list:
+ env = base_env.Clone(CONFIG_NAME=conf)
+ SConsignFile(env.File('$TOP_BUILDDIR/.sconsign').abspath)
+ for sconscript in sconscript_files:
+ target_alias = env.SConscript(sconscript, exports=['env'])
+ if target_alias:
+ target_alias_list.extend(target_alias)
+
+Default(Alias('all', target_alias_list))
+
+help_fmt = '''
+Usage: hammer [SCONS_OPTIONS] [VARIABLES] [TARGET] ...
+
+Local command-line build options:
+ --mode=CONFIG Configuration to build:
+ --mode=Debug [default]
+ --mode=Release
+ --verbose Print actual executed command lines.
+
+Supported command-line build variables:
+ LOAD=[module,...] Comma-separated list of components to load in the
+ dependency graph ('-' prefix excludes)
+ PROGRESS=type Display a progress indicator:
+ name: print each evaluated target name
+ spinner: print a spinner every 5 targets
+
+The following TARGET names can also be used as LOAD= module names:
+
+%%s
+'''
+
+if GetOption('help'):
+ def columnar_text(items, width=78, indent=2, sep=2):
+ result = []
+ colwidth = max(map(len, items)) + sep
+ cols = (width - indent) / colwidth
+ if cols < 1:
+ cols = 1
+ rows = (len(items) + cols - 1) / cols
+ indent = '%%*s' %% (indent, '')
+ sep = indent
+ for row in xrange(0, rows):
+ result.append(sep)
+ for i in xrange(row, len(items), rows):
+ result.append('%%-*s' %% (colwidth, items[i]))
+ sep = '\\n' + indent
+ result.append('\\n')
+ return ''.join(result)
+
+ load_list = set(sconscript_file_map.keys())
+ target_aliases = set(map(str, target_alias_list))
+
+ common = load_list and target_aliases
+ load_only = load_list - common
+ target_only = target_aliases - common
+ help_text = [help_fmt %% columnar_text(sorted(list(common)))]
+ if target_only:
+ fmt = "The following are additional TARGET names:\\n\\n%%s\\n"
+ help_text.append(fmt %% columnar_text(sorted(list(target_only))))
+ if load_only:
+ fmt = "The following are additional LOAD= module names:\\n\\n%%s\\n"
+ help_text.append(fmt %% columnar_text(sorted(list(load_only))))
+ Help(''.join(help_text))
+"""
+
+# TEMPLATE END
+#############################################################################
+
+
+def GenerateSConscriptWrapper(build_file, build_file_data, name,
+ output_filename, sconscript_files,
+ default_configuration):
+ """
+ Generates the "wrapper" SConscript file (analogous to the Visual Studio
+ solution) that calls all the individual target SConscript files.
+ """
+ output_dir = os.path.dirname(output_filename)
+ src_dir = build_file_data['_DEPTH']
+ src_dir_rel = gyp.common.RelativePath(src_dir, output_dir)
+ if not src_dir_rel:
+ src_dir_rel = '.'
+ scons_settings = build_file_data.get('scons_settings', {})
+ sconsbuild_dir = scons_settings.get('sconsbuild_dir', '#')
+ scons_tools = scons_settings.get('tools', ['default'])
+
+ sconscript_file_lines = ['dict(']
+ for target in sorted(sconscript_files.keys()):
+ sconscript = sconscript_files[target]
+ sconscript_file_lines.append(' %s = %r,' % (target, sconscript))
+ sconscript_file_lines.append(')')
+
+ fp = open(output_filename, 'w')
+ fp.write(header)
+ fp.write(_wrapper_template % {
+ 'default_configuration' : default_configuration,
+ 'name' : name,
+ 'scons_tools' : repr(scons_tools),
+ 'sconsbuild_dir' : repr(sconsbuild_dir),
+ 'sconscript_files' : '\n'.join(sconscript_file_lines),
+ 'src_dir' : src_dir_rel,
+ })
+ fp.close()
+
+ # Generate the SConstruct file that invokes the wrapper SConscript.
+ dir, fname = os.path.split(output_filename)
+ SConstruct = os.path.join(dir, 'SConstruct')
+ fp = open(SConstruct, 'w')
+ fp.write(header)
+ fp.write('SConscript(%s)\n' % repr(fname))
+ fp.close()
+
+
+def TargetFilename(target, build_file=None, output_suffix=''):
+ """Returns the .scons file name for the specified target.
+ """
+ if build_file is None:
+ build_file, target = gyp.common.ParseQualifiedTarget(target)[:2]
+ output_file = os.path.join(os.path.dirname(build_file),
+ target + output_suffix + '.scons')
+ return output_file
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ """
+ Generates all the output files for the specified targets.
+ """
+ options = params['options']
+
+ if options.generator_output:
+ def output_path(filename):
+ return filename.replace(params['cwd'], options.generator_output)
+ else:
+ def output_path(filename):
+ return filename
+
+ default_configuration = None
+
+ for qualified_target in target_list:
+ spec = target_dicts[qualified_target]
+ if spec['toolset'] != 'target':
+ raise Exception(
+ 'Multiple toolsets not supported in scons build (target %s)' %
+ qualified_target)
+ scons_target = SCons.Target(spec)
+ if scons_target.is_ignored:
+ continue
+
+ # TODO: assumes the default_configuration of the first target
+ # non-Default target is the correct default for all targets.
+ # Need a better model for handle variation between targets.
+ if (not default_configuration and
+ spec['default_configuration'] != 'Default'):
+ default_configuration = spec['default_configuration']
+
+ build_file, target = gyp.common.ParseQualifiedTarget(qualified_target)[:2]
+ output_file = TargetFilename(target, build_file, options.suffix)
+ if options.generator_output:
+ output_file = output_path(output_file)
+
+ if not spec.has_key('libraries'):
+ spec['libraries'] = []
+
+ # Add dependent static library targets to the 'libraries' value.
+ deps = spec.get('dependencies', [])
+ spec['scons_dependencies'] = []
+ for d in deps:
+ td = target_dicts[d]
+ target_name = td['target_name']
+ spec['scons_dependencies'].append("Alias('%s')" % target_name)
+ if td['type'] in ('static_library', 'shared_library'):
+ libname = td.get('product_name', target_name)
+ spec['libraries'].append('lib' + libname)
+ if td['type'] == 'loadable_module':
+ prereqs = spec.get('scons_prerequisites', [])
+ # TODO: parameterize with <(SHARED_LIBRARY_*) variables?
+ td_target = SCons.Target(td)
+ td_target.target_prefix = '${SHLIBPREFIX}'
+ td_target.target_suffix = '${SHLIBSUFFIX}'
+
+ GenerateSConscript(output_file, spec, build_file, data[build_file])
+
+ if not default_configuration:
+ default_configuration = 'Default'
+
+ for build_file in sorted(data.keys()):
+ path, ext = os.path.splitext(build_file)
+ if ext != '.gyp':
+ continue
+ output_dir, basename = os.path.split(path)
+ output_filename = path + '_main' + options.suffix + '.scons'
+
+ all_targets = gyp.common.AllTargets(target_list, target_dicts, build_file)
+ sconscript_files = {}
+ for t in all_targets:
+ scons_target = SCons.Target(target_dicts[t])
+ if scons_target.is_ignored:
+ continue
+ bf, target = gyp.common.ParseQualifiedTarget(t)[:2]
+ target_filename = TargetFilename(target, bf, options.suffix)
+ tpath = gyp.common.RelativePath(target_filename, output_dir)
+ sconscript_files[target] = tpath
+
+ output_filename = output_path(output_filename)
+ if sconscript_files:
+ GenerateSConscriptWrapper(build_file, data[build_file], basename,
+ output_filename, sconscript_files,
+ default_configuration)
diff --git a/Source/ThirdParty/gyp/pylib/gyp/generator/xcode.py b/Source/ThirdParty/gyp/pylib/gyp/generator/xcode.py
new file mode 100644
index 000000000..c7ce5b0f3
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/generator/xcode.py
@@ -0,0 +1,1201 @@
+#!/usr/bin/python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import filecmp
+import gyp.common
+import gyp.xcodeproj_file
+import errno
+import os
+import posixpath
+import re
+import shutil
+import subprocess
+import tempfile
+
+
+# Project files generated by this module will use _intermediate_var as a
+# custom Xcode setting whose value is a DerivedSources-like directory that's
+# project-specific and configuration-specific. The normal choice,
+# DERIVED_FILE_DIR, is target-specific, which is thought to be too restrictive
+# as it is likely that multiple targets within a single project file will want
+# to access the same set of generated files. The other option,
+# PROJECT_DERIVED_FILE_DIR, is unsuitable because while it is project-specific,
+# it is not configuration-specific. INTERMEDIATE_DIR is defined as
+# $(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION).
+_intermediate_var = 'INTERMEDIATE_DIR'
+
+# SHARED_INTERMEDIATE_DIR is the same, except that it is shared among all
+# targets that share the same BUILT_PRODUCTS_DIR.
+_shared_intermediate_var = 'SHARED_INTERMEDIATE_DIR'
+
+_library_search_paths_var = 'LIBRARY_SEARCH_PATHS'
+
+generator_default_variables = {
+ 'EXECUTABLE_PREFIX': '',
+ 'EXECUTABLE_SUFFIX': '',
+ 'STATIC_LIB_PREFIX': 'lib',
+ 'SHARED_LIB_PREFIX': 'lib',
+ 'STATIC_LIB_SUFFIX': '.a',
+ 'SHARED_LIB_SUFFIX': '.dylib',
+ # INTERMEDIATE_DIR is a place for targets to build up intermediate products.
+ # It is specific to each build environment. It is only guaranteed to exist
+ # and be constant within the context of a project, corresponding to a single
+ # input file. Some build environments may allow their intermediate directory
+ # to be shared on a wider scale, but this is not guaranteed.
+ 'INTERMEDIATE_DIR': '$(%s)' % _intermediate_var,
+ 'OS': 'mac',
+ 'PRODUCT_DIR': '$(BUILT_PRODUCTS_DIR)',
+ 'LIB_DIR': '$(BUILT_PRODUCTS_DIR)',
+ 'RULE_INPUT_ROOT': '$(INPUT_FILE_BASE)',
+ 'RULE_INPUT_EXT': '$(INPUT_FILE_SUFFIX)',
+ 'RULE_INPUT_NAME': '$(INPUT_FILE_NAME)',
+ 'RULE_INPUT_PATH': '$(INPUT_FILE_PATH)',
+ 'SHARED_INTERMEDIATE_DIR': '$(%s)' % _shared_intermediate_var,
+ 'CONFIGURATION_NAME': '$(CONFIGURATION)',
+}
+
+# The Xcode-specific sections that hold paths.
+generator_additional_path_sections = [
+ 'mac_bundle_resources',
+ 'mac_framework_headers',
+ 'mac_framework_private_headers',
+ # 'mac_framework_dirs', input already handles _dirs endings.
+]
+
+# The Xcode-specific keys that exist on targets and aren't moved down to
+# configurations.
+generator_additional_non_configuration_keys = [
+ 'mac_bundle',
+ 'mac_bundle_resources',
+ 'mac_framework_headers',
+ 'mac_framework_private_headers',
+ 'xcode_create_dependents_test_runner',
+]
+
+# We want to let any rules apply to files that are resources also.
+generator_extra_sources_for_rules = [
+ 'mac_bundle_resources',
+ 'mac_framework_headers',
+ 'mac_framework_private_headers',
+]
+
+# Xcode's standard set of library directories, which don't need to be duplicated
+# in LIBRARY_SEARCH_PATHS. This list is not exhaustive, but that's okay.
+xcode_standard_library_dirs = frozenset([
+ '$(SDKROOT)/usr/lib',
+ '$(SDKROOT)/usr/local/lib',
+])
+
+def CreateXCConfigurationList(configuration_names):
+ xccl = gyp.xcodeproj_file.XCConfigurationList({'buildConfigurations': []})
+ if len(configuration_names) == 0:
+ configuration_names = ['Default']
+ for configuration_name in configuration_names:
+ xcbc = gyp.xcodeproj_file.XCBuildConfiguration({
+ 'name': configuration_name})
+ xccl.AppendProperty('buildConfigurations', xcbc)
+ xccl.SetProperty('defaultConfigurationName', configuration_names[0])
+ return xccl
+
+
+class XcodeProject(object):
+ def __init__(self, gyp_path, path, build_file_dict):
+ self.gyp_path = gyp_path
+ self.path = path
+ self.project = gyp.xcodeproj_file.PBXProject(path=path)
+ projectDirPath = gyp.common.RelativePath(
+ os.path.dirname(os.path.abspath(self.gyp_path)),
+ os.path.dirname(path) or '.')
+ self.project.SetProperty('projectDirPath', projectDirPath)
+ self.project_file = \
+ gyp.xcodeproj_file.XCProjectFile({'rootObject': self.project})
+ self.build_file_dict = build_file_dict
+
+ # TODO(mark): add destructor that cleans up self.path if created_dir is
+ # True and things didn't complete successfully. Or do something even
+ # better with "try"?
+ self.created_dir = False
+ try:
+ os.makedirs(self.path)
+ self.created_dir = True
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ def Finalize1(self, xcode_targets, serialize_all_tests):
+ # Collect a list of all of the build configuration names used by the
+ # various targets in the file. It is very heavily advised to keep each
+ # target in an entire project (even across multiple project files) using
+ # the same set of configuration names.
+ configurations = []
+ for xct in self.project.GetProperty('targets'):
+ xccl = xct.GetProperty('buildConfigurationList')
+ xcbcs = xccl.GetProperty('buildConfigurations')
+ for xcbc in xcbcs:
+ name = xcbc.GetProperty('name')
+ if name not in configurations:
+ configurations.append(name)
+
+ # Replace the XCConfigurationList attached to the PBXProject object with
+ # a new one specifying all of the configuration names used by the various
+ # targets.
+ try:
+ xccl = CreateXCConfigurationList(configurations)
+ self.project.SetProperty('buildConfigurationList', xccl)
+ except:
+ import sys
+ sys.stderr.write("Problem with gyp file %s\n" % self.gyp_path)
+ raise
+
+ # The need for this setting is explained above where _intermediate_var is
+ # defined. The comments below about wanting to avoid project-wide build
+ # settings apply here too, but this needs to be set on a project-wide basis
+ # so that files relative to the _intermediate_var setting can be displayed
+ # properly in the Xcode UI.
+ #
+ # Note that for configuration-relative files such as anything relative to
+ # _intermediate_var, for the purposes of UI tree view display, Xcode will
+ # only resolve the configuration name once, when the project file is
+ # opened. If the active build configuration is changed, the project file
+ # must be closed and reopened if it is desired for the tree view to update.
+ # This is filed as Apple radar 6588391.
+ xccl.SetBuildSetting(_intermediate_var,
+ '$(PROJECT_DERIVED_FILE_DIR)/$(CONFIGURATION)')
+ xccl.SetBuildSetting(_shared_intermediate_var,
+ '$(SYMROOT)/DerivedSources/$(CONFIGURATION)')
+
+ # Set user-specified project-wide build settings and config files. This
+ # is intended to be used very sparingly. Really, almost everything should
+ # go into target-specific build settings sections. The project-wide
+ # settings are only intended to be used in cases where Xcode attempts to
+ # resolve variable references in a project context as opposed to a target
+ # context, such as when resolving sourceTree references while building up
+ # the tree tree view for UI display.
+ # Any values set globally are applied to all configurations, then any
+ # per-configuration values are applied.
+ for xck, xcv in self.build_file_dict.get('xcode_settings', {}).iteritems():
+ xccl.SetBuildSetting(xck, xcv)
+ if 'xcode_config_file' in self.build_file_dict:
+ config_ref = self.project.AddOrGetFileInRootGroup(
+ self.build_file_dict['xcode_config_file'])
+ xccl.SetBaseConfiguration(config_ref)
+ build_file_configurations = self.build_file_dict.get('configurations', {})
+ if build_file_configurations:
+ for config_name in configurations:
+ build_file_configuration_named = \
+ build_file_configurations.get(config_name, {})
+ if build_file_configuration_named:
+ xcc = xccl.ConfigurationNamed(config_name)
+ for xck, xcv in build_file_configuration_named.get('xcode_settings',
+ {}).iteritems():
+ xcc.SetBuildSetting(xck, xcv)
+ if 'xcode_config_file' in build_file_configuration_named:
+ config_ref = self.project.AddOrGetFileInRootGroup(
+ build_file_configurations[config_name]['xcode_config_file'])
+ xcc.SetBaseConfiguration(config_ref)
+
+ # Sort the targets based on how they appeared in the input.
+ # TODO(mark): Like a lot of other things here, this assumes internal
+ # knowledge of PBXProject - in this case, of its "targets" property.
+
+ # ordinary_targets are ordinary targets that are already in the project
+ # file. run_test_targets are the targets that run unittests and should be
+ # used for the Run All Tests target. support_targets are the action/rule
+ # targets used by GYP file targets, just kept for the assert check.
+ ordinary_targets = []
+ run_test_targets = []
+ support_targets = []
+
+ # targets is full list of targets in the project.
+ targets = []
+
+ # does the it define it's own "all"?
+ has_custom_all = False
+
+ # targets_for_all is the list of ordinary_targets that should be listed
+ # in this project's "All" target. It includes each non_runtest_target
+ # that does not have suppress_wildcard set.
+ targets_for_all = []
+
+ for target in self.build_file_dict['targets']:
+ target_name = target['target_name']
+ toolset = target['toolset']
+ qualified_target = gyp.common.QualifiedTarget(self.gyp_path, target_name,
+ toolset)
+ xcode_target = xcode_targets[qualified_target]
+ # Make sure that the target being added to the sorted list is already in
+ # the unsorted list.
+ assert xcode_target in self.project._properties['targets']
+ targets.append(xcode_target)
+ ordinary_targets.append(xcode_target)
+ if xcode_target.support_target:
+ support_targets.append(xcode_target.support_target)
+ targets.append(xcode_target.support_target)
+
+ if not int(target.get('suppress_wildcard', False)):
+ targets_for_all.append(xcode_target)
+
+ if target_name.lower() == 'all':
+ has_custom_all = True;
+
+ # If this target has a 'run_as' attribute, add its target to the
+ # targets, and add it to the test targets.
+ if target.get('run_as'):
+ # Make a target to run something. It should have one
+ # dependency, the parent xcode target.
+ xccl = CreateXCConfigurationList(configurations)
+ run_target = gyp.xcodeproj_file.PBXAggregateTarget({
+ 'name': 'Run ' + target_name,
+ 'productName': xcode_target.GetProperty('productName'),
+ 'buildConfigurationList': xccl,
+ },
+ parent=self.project)
+ run_target.AddDependency(xcode_target)
+
+ command = target['run_as']
+ script = ''
+ if command.get('working_directory'):
+ script = script + 'cd "%s"\n' % \
+ gyp.xcodeproj_file.ConvertVariablesToShellSyntax(
+ command.get('working_directory'))
+
+ if command.get('environment'):
+ script = script + "\n".join(
+ ['export %s="%s"' %
+ (key, gyp.xcodeproj_file.ConvertVariablesToShellSyntax(val))
+ for (key, val) in command.get('environment').iteritems()]) + "\n"
+
+ # Some test end up using sockets, files on disk, etc. and can get
+ # confused if more then one test runs at a time. The generator
+ # flag 'xcode_serialize_all_test_runs' controls the forcing of all
+ # tests serially. It defaults to True. To get serial runs this
+ # little bit of python does the same as the linux flock utility to
+ # make sure only one runs at a time.
+ command_prefix = ''
+ if serialize_all_tests:
+ command_prefix = \
+"""python -c "import fcntl, subprocess, sys
+file = open('$TMPDIR/GYP_serialize_test_runs', 'a')
+fcntl.flock(file.fileno(), fcntl.LOCK_EX)
+sys.exit(subprocess.call(sys.argv[1:]))" """
+
+ # If we were unable to exec for some reason, we want to exit
+ # with an error, and fixup variable references to be shell
+ # syntax instead of xcode syntax.
+ script = script + 'exec ' + command_prefix + '%s\nexit 1\n' % \
+ gyp.xcodeproj_file.ConvertVariablesToShellSyntax(
+ gyp.common.EncodePOSIXShellList(command.get('action')))
+
+ ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
+ 'shellScript': script,
+ 'showEnvVarsInLog': 0,
+ })
+ run_target.AppendProperty('buildPhases', ssbp)
+
+ # Add the run target to the project file.
+ targets.append(run_target)
+ run_test_targets.append(run_target)
+ xcode_target.test_runner = run_target
+
+
+ # Make sure that the list of targets being replaced is the same length as
+ # the one replacing it, but allow for the added test runner targets.
+ assert len(self.project._properties['targets']) == \
+ len(ordinary_targets) + len(support_targets)
+
+ self.project._properties['targets'] = targets
+
+ # Get rid of unnecessary levels of depth in groups like the Source group.
+ self.project.RootGroupsTakeOverOnlyChildren(True)
+
+ # Sort the groups nicely. Do this after sorting the targets, because the
+ # Products group is sorted based on the order of the targets.
+ self.project.SortGroups()
+
+ # Create an "All" target if there's more than one target in this project
+ # file and the project didn't define its own "All" target. Put a generated
+ # "All" target first so that people opening up the project for the first
+ # time will build everything by default.
+ if len(targets_for_all) > 1 and not has_custom_all:
+ xccl = CreateXCConfigurationList(configurations)
+ all_target = gyp.xcodeproj_file.PBXAggregateTarget(
+ {
+ 'buildConfigurationList': xccl,
+ 'name': 'All',
+ },
+ parent=self.project)
+
+ for target in targets_for_all:
+ all_target.AddDependency(target)
+
+ # TODO(mark): This is evil because it relies on internal knowledge of
+ # PBXProject._properties. It's important to get the "All" target first,
+ # though.
+ self.project._properties['targets'].insert(0, all_target)
+
+ # The same, but for run_test_targets.
+ if len(run_test_targets) > 1:
+ xccl = CreateXCConfigurationList(configurations)
+ run_all_tests_target = gyp.xcodeproj_file.PBXAggregateTarget(
+ {
+ 'buildConfigurationList': xccl,
+ 'name': 'Run All Tests',
+ },
+ parent=self.project)
+ for run_test_target in run_test_targets:
+ run_all_tests_target.AddDependency(run_test_target)
+
+ # Insert after the "All" target, which must exist if there is more than
+ # one run_test_target.
+ self.project._properties['targets'].insert(1, run_all_tests_target)
+
+ def Finalize2(self, xcode_targets, xcode_target_to_target_dict):
+ # Finalize2 needs to happen in a separate step because the process of
+ # updating references to other projects depends on the ordering of targets
+ # within remote project files. Finalize1 is responsible for sorting duty,
+ # and once all project files are sorted, Finalize2 can come in and update
+ # these references.
+
+ # To support making a "test runner" target that will run all the tests
+ # that are direct dependents of any given target, we look for
+ # xcode_create_dependents_test_runner being set on an Aggregate target,
+ # and generate a second target that will run the tests runners found under
+ # the marked target.
+ for bf_tgt in self.build_file_dict['targets']:
+ if int(bf_tgt.get('xcode_create_dependents_test_runner', 0)):
+ tgt_name = bf_tgt['target_name']
+ toolset = bf_tgt['toolset']
+ qualified_target = gyp.common.QualifiedTarget(self.gyp_path,
+ tgt_name, toolset)
+ xcode_target = xcode_targets[qualified_target]
+ if isinstance(xcode_target, gyp.xcodeproj_file.PBXAggregateTarget):
+ # Collect all the run test targets.
+ all_run_tests = []
+ pbxtds = xcode_target.GetProperty('dependencies')
+ for pbxtd in pbxtds:
+ pbxcip = pbxtd.GetProperty('targetProxy')
+ dependency_xct = pbxcip.GetProperty('remoteGlobalIDString')
+ if hasattr(dependency_xct, 'test_runner'):
+ all_run_tests.append(dependency_xct.test_runner)
+
+ # Directly depend on all the runners as they depend on the target
+ # that builds them.
+ if len(all_run_tests) > 0:
+ run_all_target = gyp.xcodeproj_file.PBXAggregateTarget({
+ 'name': 'Run %s Tests' % tgt_name,
+ 'productName': tgt_name,
+ },
+ parent=self.project)
+ for run_test_target in all_run_tests:
+ run_all_target.AddDependency(run_test_target)
+
+ # Insert the test runner after the related target.
+ idx = self.project._properties['targets'].index(xcode_target)
+ self.project._properties['targets'].insert(idx + 1, run_all_target)
+
+ # Update all references to other projects, to make sure that the lists of
+ # remote products are complete. Otherwise, Xcode will fill them in when
+ # it opens the project file, which will result in unnecessary diffs.
+ # TODO(mark): This is evil because it relies on internal knowledge of
+ # PBXProject._other_pbxprojects.
+ for other_pbxproject in self.project._other_pbxprojects.keys():
+ self.project.AddOrGetProjectReference(other_pbxproject)
+
+ self.project.SortRemoteProductReferences()
+
+ # Give everything an ID.
+ self.project_file.ComputeIDs()
+
+ # Make sure that no two objects in the project file have the same ID. If
+ # multiple objects wind up with the same ID, upon loading the file, Xcode
+ # will only recognize one object (the last one in the file?) and the
+ # results are unpredictable.
+ self.project_file.EnsureNoIDCollisions()
+
+ def Write(self):
+ # Write the project file to a temporary location first. Xcode watches for
+ # changes to the project file and presents a UI sheet offering to reload
+ # the project when it does change. However, in some cases, especially when
+ # multiple projects are open or when Xcode is busy, things don't work so
+ # seamlessly. Sometimes, Xcode is able to detect that a project file has
+ # changed but can't unload it because something else is referencing it.
+ # To mitigate this problem, and to avoid even having Xcode present the UI
+ # sheet when an open project is rewritten for inconsequential changes, the
+ # project file is written to a temporary file in the xcodeproj directory
+ # first. The new temporary file is then compared to the existing project
+ # file, if any. If they differ, the new file replaces the old; otherwise,
+ # the new project file is simply deleted. Xcode properly detects a file
+ # being renamed over an open project file as a change and so it remains
+ # able to present the "project file changed" sheet under this system.
+ # Writing to a temporary file first also avoids the possible problem of
+ # Xcode rereading an incomplete project file.
+ (output_fd, new_pbxproj_path) = \
+ tempfile.mkstemp(suffix='.tmp', prefix='project.pbxproj.gyp.',
+ dir=self.path)
+
+ try:
+ output_file = os.fdopen(output_fd, 'wb')
+
+ self.project_file.Print(output_file)
+ output_file.close()
+
+ pbxproj_path = os.path.join(self.path, 'project.pbxproj')
+
+ same = False
+ try:
+ same = filecmp.cmp(pbxproj_path, new_pbxproj_path, False)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+
+ if same:
+ # The new file is identical to the old one, just get rid of the new
+ # one.
+ os.unlink(new_pbxproj_path)
+ else:
+ # The new file is different from the old one, or there is no old one.
+ # Rename the new file to the permanent name.
+ #
+ # tempfile.mkstemp uses an overly restrictive mode, resulting in a
+ # file that can only be read by the owner, regardless of the umask.
+ # There's no reason to not respect the umask here, which means that
+ # an extra hoop is required to fetch it and reset the new file's mode.
+ #
+ # No way to get the umask without setting a new one? Set a safe one
+ # and then set it back to the old value.
+ umask = os.umask(077)
+ os.umask(umask)
+
+ os.chmod(new_pbxproj_path, 0666 & ~umask)
+ os.rename(new_pbxproj_path, pbxproj_path)
+
+ except Exception:
+ # Don't leave turds behind. In fact, if this code was responsible for
+ # creating the xcodeproj directory, get rid of that too.
+ os.unlink(new_pbxproj_path)
+ if self.created_dir:
+ shutil.rmtree(self.path, True)
+ raise
+
+
+cached_xcode_version = None
+def InstalledXcodeVersion():
+ """Fetches the installed version of Xcode, returns empty string if it is
+ unable to figure it out."""
+
+ global cached_xcode_version
+ if not cached_xcode_version is None:
+ return cached_xcode_version
+
+ # Default to an empty string
+ cached_xcode_version = ''
+
+ # Collect the xcodebuild's version information.
+ try:
+ import subprocess
+ cmd = ['/usr/bin/xcodebuild', '-version']
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ xcodebuild_version_info = proc.communicate()[0]
+ # Any error, return empty string
+ if proc.returncode:
+ xcodebuild_version_info = ''
+ except OSError:
+ # We failed to launch the tool
+ xcodebuild_version_info = ''
+
+ # Pull out the Xcode version itself.
+ match_line = re.search('^Xcode (.*)$', xcodebuild_version_info, re.MULTILINE)
+ if match_line:
+ cached_xcode_version = match_line.group(1)
+ # Done!
+ return cached_xcode_version
+
+
+def AddSourceToTarget(source, pbxp, xct):
+ # TODO(mark): Perhaps source_extensions and library_extensions can be made a
+ # little bit fancier.
+ source_extensions = ['c', 'cc', 'cpp', 'cxx', 'm', 'mm', 's']
+
+ # .o is conceptually more of a "source" than a "library," but Xcode thinks
+ # of "sources" as things to compile and "libraries" (or "frameworks") as
+ # things to link with. Adding an object file to an Xcode target's frameworks
+ # phase works properly.
+ library_extensions = ['a', 'dylib', 'framework', 'o']
+
+ basename = posixpath.basename(source)
+ (root, ext) = posixpath.splitext(basename)
+ if ext != '':
+ ext = ext[1:].lower()
+
+ if ext in source_extensions:
+ xct.SourcesPhase().AddFile(source)
+ elif ext in library_extensions:
+ xct.FrameworksPhase().AddFile(source)
+ else:
+ # Files that aren't added to a sources or frameworks build phase can still
+ # go into the project file, just not as part of a build phase.
+ pbxp.AddOrGetFileInRootGroup(source)
+
+
+def AddResourceToTarget(resource, pbxp, xct):
+ # TODO(mark): Combine with AddSourceToTarget above? Or just inline this call
+ # where it's used.
+ xct.ResourcesPhase().AddFile(resource)
+
+
+def AddHeaderToTarget(header, pbxp, xct, is_public):
+ # TODO(mark): Combine with AddSourceToTarget above? Or just inline this call
+ # where it's used.
+ settings = '{ATTRIBUTES = (%s, ); }' % ('Private', 'Public')[is_public]
+ xct.HeadersPhase().AddFile(header, settings)
+
+
+_xcode_variable_re = re.compile('(\$\((.*?)\))')
+def ExpandXcodeVariables(string, expansions):
+ """Expands Xcode-style $(VARIABLES) in string per the expansions dict.
+
+ In some rare cases, it is appropriate to expand Xcode variables when a
+ project file is generated. For any substring $(VAR) in string, if VAR is a
+ key in the expansions dict, $(VAR) will be replaced with expansions[VAR].
+ Any $(VAR) substring in string for which VAR is not a key in the expansions
+ dict will remain in the returned string.
+ """
+
+ matches = _xcode_variable_re.findall(string)
+ if matches == None:
+ return string
+
+ matches.reverse()
+ for match in matches:
+ (to_replace, variable) = match
+ if not variable in expansions:
+ continue
+
+ replacement = expansions[variable]
+ string = re.sub(re.escape(to_replace), replacement, string)
+
+ return string
+
+
+def EscapeXCodeArgument(s):
+ """We must escape the arguments that we give to XCode so that it knows not to
+ split on spaces and to respect backslash and quote literals."""
+ s = s.replace('\\', '\\\\')
+ s = s.replace('"', '\\"')
+ return '"' + s + '"'
+
+
+def GenerateOutput(target_list, target_dicts, data, params):
+ options = params['options']
+ generator_flags = params.get('generator_flags', {})
+ parallel_builds = generator_flags.get('xcode_parallel_builds', True)
+ serialize_all_tests = \
+ generator_flags.get('xcode_serialize_all_test_runs', True)
+ project_version = generator_flags.get('xcode_project_version', None)
+ skip_excluded_files = \
+ not generator_flags.get('xcode_list_excluded_files', True)
+ xcode_projects = {}
+ for build_file, build_file_dict in data.iteritems():
+ (build_file_root, build_file_ext) = os.path.splitext(build_file)
+ if build_file_ext != '.gyp':
+ continue
+ xcodeproj_path = build_file_root + options.suffix + '.xcodeproj'
+ if options.generator_output:
+ xcodeproj_path = os.path.join(options.generator_output, xcodeproj_path)
+ xcp = XcodeProject(build_file, xcodeproj_path, build_file_dict)
+ xcode_projects[build_file] = xcp
+ pbxp = xcp.project
+
+ if parallel_builds:
+ pbxp.SetProperty('attributes',
+ {'BuildIndependentTargetsInParallel': 'YES'})
+ if project_version:
+ xcp.project_file.SetXcodeVersion(project_version)
+
+ main_group = pbxp.GetProperty('mainGroup')
+ build_group = gyp.xcodeproj_file.PBXGroup({'name': 'Build'})
+ main_group.AppendChild(build_group)
+ for included_file in build_file_dict['included_files']:
+ build_group.AddOrGetFileByPath(included_file, False)
+
+ xcode_targets = {}
+ xcode_target_to_target_dict = {}
+ for qualified_target in target_list:
+ [build_file, target_name, toolset] = \
+ gyp.common.ParseQualifiedTarget(qualified_target)
+
+ spec = target_dicts[qualified_target]
+ if spec['toolset'] != 'target':
+ raise Exception(
+ 'Multiple toolsets not supported in xcode build (target %s)' %
+ qualified_target)
+ configuration_names = [spec['default_configuration']]
+ for configuration_name in sorted(spec['configurations'].keys()):
+ if configuration_name not in configuration_names:
+ configuration_names.append(configuration_name)
+ xcp = xcode_projects[build_file]
+ pbxp = xcp.project
+
+ # Set up the configurations for the target according to the list of names
+ # supplied.
+ xccl = CreateXCConfigurationList(configuration_names)
+
+ # Create an XCTarget subclass object for the target. The type with
+ # "+bundle" appended will be used if the target has "mac_bundle" set.
+ # loadable_modules not in a mac_bundle are mapped to
+ # com.googlecode.gyp.xcode.bundle, a pseudo-type that xcode.py interprets
+ # to create a single-file mh_bundle.
+ _types = {
+ 'executable': 'com.apple.product-type.tool',
+ 'loadable_module': 'com.googlecode.gyp.xcode.bundle',
+ 'shared_library': 'com.apple.product-type.library.dynamic',
+ 'static_library': 'com.apple.product-type.library.static',
+ 'executable+bundle': 'com.apple.product-type.application',
+ 'loadable_module+bundle': 'com.apple.product-type.bundle',
+ 'shared_library+bundle': 'com.apple.product-type.framework',
+ }
+
+ target_properties = {
+ 'buildConfigurationList': xccl,
+ 'name': target_name,
+ }
+
+ type = spec['type']
+ is_bundle = int(spec.get('mac_bundle', 0))
+ if type != 'none':
+ type_bundle_key = type
+ if is_bundle:
+ type_bundle_key += '+bundle'
+ xctarget_type = gyp.xcodeproj_file.PBXNativeTarget
+ try:
+ target_properties['productType'] = _types[type_bundle_key]
+ except KeyError, e:
+ gyp.common.ExceptionAppend(e, "-- unknown product type while "
+ "writing target %s" % target_name)
+ raise
+ else:
+ xctarget_type = gyp.xcodeproj_file.PBXAggregateTarget
+
+ target_product_name = spec.get('product_name')
+ if target_product_name is not None:
+ target_properties['productName'] = target_product_name
+
+ xct = xctarget_type(target_properties, parent=pbxp,
+ force_outdir=spec.get('product_dir'),
+ force_prefix=spec.get('product_prefix'),
+ force_extension=spec.get('product_extension'))
+ pbxp.AppendProperty('targets', xct)
+ xcode_targets[qualified_target] = xct
+ xcode_target_to_target_dict[xct] = spec
+
+ spec_actions = spec.get('actions', [])
+ spec_rules = spec.get('rules', [])
+
+ # Xcode has some "issues" with checking dependencies for the "Compile
+ # sources" step with any source files/headers generated by actions/rules.
+ # To work around this, if a target is building anything directly (not
+ # type "none"), then a second target as used to run the GYP actions/rules
+ # and is made a dependency of this target. This way the work is done
+ # before the dependency checks for what should be recompiled.
+ support_xct = None
+ if type != 'none' and (spec_actions or spec_rules):
+ support_xccl = CreateXCConfigurationList(configuration_names);
+ support_target_properties = {
+ 'buildConfigurationList': support_xccl,
+ 'name': target_name + ' Support',
+ }
+ if target_product_name:
+ support_target_properties['productName'] = \
+ target_product_name + ' Support'
+ support_xct = \
+ gyp.xcodeproj_file.PBXAggregateTarget(support_target_properties,
+ parent=pbxp)
+ pbxp.AppendProperty('targets', support_xct)
+ xct.AddDependency(support_xct)
+ # Hang the support target off the main target so it can be tested/found
+ # by the generator during Finalize.
+ xct.support_target = support_xct
+
+ prebuild_index = 0
+
+ # Add custom shell script phases for "actions" sections.
+ for action in spec_actions:
+ # There's no need to write anything into the script to ensure that the
+ # output directories already exist, because Xcode will look at the
+ # declared outputs and automatically ensure that they exist for us.
+
+ # Do we have a message to print when this action runs?
+ message = action.get('message')
+ if message:
+ message = 'echo note: ' + gyp.common.EncodePOSIXShellArgument(message)
+ else:
+ message = ''
+
+ # Turn the list into a string that can be passed to a shell.
+ action_string = gyp.common.EncodePOSIXShellList(action['action'])
+
+ # Convert Xcode-type variable references to sh-compatible environment
+ # variable references.
+ message_sh = gyp.xcodeproj_file.ConvertVariablesToShellSyntax(message)
+ action_string_sh = gyp.xcodeproj_file.ConvertVariablesToShellSyntax(
+ action_string)
+
+ script = ''
+ # Include the optional message
+ if message_sh:
+ script += message_sh + '\n'
+ # Be sure the script runs in exec, and that if exec fails, the script
+ # exits signalling an error.
+ script += 'exec ' + action_string_sh + '\nexit 1\n'
+ ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
+ 'inputPaths': action['inputs'],
+ 'name': 'Action "' + action['action_name'] + '"',
+ 'outputPaths': action['outputs'],
+ 'shellScript': script,
+ 'showEnvVarsInLog': 0,
+ })
+
+ if support_xct:
+ support_xct.AppendProperty('buildPhases', ssbp)
+ else:
+ # TODO(mark): this assumes too much knowledge of the internals of
+ # xcodeproj_file; some of these smarts should move into xcodeproj_file
+ # itself.
+ xct._properties['buildPhases'].insert(prebuild_index, ssbp)
+ prebuild_index = prebuild_index + 1
+
+ # TODO(mark): Should verify that at most one of these is specified.
+ if int(action.get('process_outputs_as_sources', False)):
+ for output in action['outputs']:
+ AddSourceToTarget(output, pbxp, xct)
+
+ if int(action.get('process_outputs_as_mac_bundle_resources', False)):
+ for output in action['outputs']:
+ AddResourceToTarget(output, pbxp, xct)
+
+ # tgt_mac_bundle_resources holds the list of bundle resources so
+ # the rule processing can check against it.
+ if is_bundle:
+ tgt_mac_bundle_resources = spec.get('mac_bundle_resources', [])
+ else:
+ tgt_mac_bundle_resources = []
+
+ # Add custom shell script phases driving "make" for "rules" sections.
+ #
+ # Xcode's built-in rule support is almost powerful enough to use directly,
+ # but there are a few significant deficiencies that render them unusable.
+ # There are workarounds for some of its inadequacies, but in aggregate,
+ # the workarounds added complexity to the generator, and some workarounds
+ # actually require input files to be crafted more carefully than I'd like.
+ # Consequently, until Xcode rules are made more capable, "rules" input
+ # sections will be handled in Xcode output by shell script build phases
+ # performed prior to the compilation phase.
+ #
+ # The following problems with Xcode rules were found. The numbers are
+ # Apple radar IDs. I hope that these shortcomings are addressed, I really
+ # liked having the rules handled directly in Xcode during the period that
+ # I was prototyping this.
+ #
+ # 6588600 Xcode compiles custom script rule outputs too soon, compilation
+ # fails. This occurs when rule outputs from distinct inputs are
+ # interdependent. The only workaround is to put rules and their
+ # inputs in a separate target from the one that compiles the rule
+ # outputs. This requires input file cooperation and it means that
+ # process_outputs_as_sources is unusable.
+ # 6584932 Need to declare that custom rule outputs should be excluded from
+ # compilation. A possible workaround is to lie to Xcode about a
+ # rule's output, giving it a dummy file it doesn't know how to
+ # compile. The rule action script would need to touch the dummy.
+ # 6584839 I need a way to declare additional inputs to a custom rule.
+ # A possible workaround is a shell script phase prior to
+ # compilation that touches a rule's primary input files if any
+ # would-be additional inputs are newer than the output. Modifying
+ # the source tree - even just modification times - feels dirty.
+ # 6564240 Xcode "custom script" build rules always dump all environment
+ # variables. This is a low-prioroty problem and is not a
+ # show-stopper.
+ rules_by_ext = {}
+ for rule in spec_rules:
+ rules_by_ext[rule['extension']] = rule
+
+ # First, some definitions:
+ #
+ # A "rule source" is a file that was listed in a target's "sources"
+ # list and will have a rule applied to it on the basis of matching the
+ # rule's "extensions" attribute. Rule sources are direct inputs to
+ # rules.
+ #
+ # Rule definitions may specify additional inputs in their "inputs"
+ # attribute. These additional inputs are used for dependency tracking
+ # purposes.
+ #
+ # A "concrete output" is a rule output with input-dependent variables
+ # resolved. For example, given a rule with:
+ # 'extension': 'ext', 'outputs': ['$(INPUT_FILE_BASE).cc'],
+ # if the target's "sources" list contained "one.ext" and "two.ext",
+ # the "concrete output" for rule input "two.ext" would be "two.cc". If
+ # a rule specifies multiple outputs, each input file that the rule is
+ # applied to will have the same number of concrete outputs.
+ #
+ # If any concrete outputs are outdated or missing relative to their
+ # corresponding rule_source or to any specified additional input, the
+ # rule action must be performed to generate the concrete outputs.
+
+ # concrete_outputs_by_rule_source will have an item at the same index
+ # as the rule['rule_sources'] that it corresponds to. Each item is a
+ # list of all of the concrete outputs for the rule_source.
+ concrete_outputs_by_rule_source = []
+
+ # concrete_outputs_all is a flat list of all concrete outputs that this
+ # rule is able to produce, given the known set of input files
+ # (rule_sources) that apply to it.
+ concrete_outputs_all = []
+
+ # messages & actions are keyed by the same indices as rule['rule_sources']
+ # and concrete_outputs_by_rule_source. They contain the message and
+ # action to perform after resolving input-dependent variables. The
+ # message is optional, in which case None is stored for each rule source.
+ messages = []
+ actions = []
+
+ for rule_source in rule.get('rule_sources', []):
+ rule_source_basename = posixpath.basename(rule_source)
+ (rule_source_root, rule_source_ext) = \
+ posixpath.splitext(rule_source_basename)
+
+ # These are the same variable names that Xcode uses for its own native
+ # rule support. Because Xcode's rule engine is not being used, they
+ # need to be expanded as they are written to the makefile.
+ rule_input_dict = {
+ 'INPUT_FILE_BASE': rule_source_root,
+ 'INPUT_FILE_SUFFIX': rule_source_ext,
+ 'INPUT_FILE_NAME': rule_source_basename,
+ 'INPUT_FILE_PATH': rule_source,
+ }
+
+ concrete_outputs_for_this_rule_source = []
+ for output in rule.get('outputs', []):
+ # Fortunately, Xcode and make both use $(VAR) format for their
+ # variables, so the expansion is the only transformation necessary.
+ # Any remaning $(VAR)-type variables in the string can be given
+ # directly to make, which will pick up the correct settings from
+ # what Xcode puts into the environment.
+ concrete_output = ExpandXcodeVariables(output, rule_input_dict)
+ concrete_outputs_for_this_rule_source.append(concrete_output)
+
+ # Add all concrete outputs to the project.
+ pbxp.AddOrGetFileInRootGroup(concrete_output)
+
+ concrete_outputs_by_rule_source.append( \
+ concrete_outputs_for_this_rule_source)
+ concrete_outputs_all.extend(concrete_outputs_for_this_rule_source)
+
+ # TODO(mark): Should verify that at most one of these is specified.
+ if int(rule.get('process_outputs_as_sources', False)):
+ for output in concrete_outputs_for_this_rule_source:
+ AddSourceToTarget(output, pbxp, xct)
+
+ # If the file came from the mac_bundle_resources list or if the rule
+ # is marked to process outputs as bundle resource, do so.
+ was_mac_bundle_resource = rule_source in tgt_mac_bundle_resources
+ if was_mac_bundle_resource or \
+ int(rule.get('process_outputs_as_mac_bundle_resources', False)):
+ for output in concrete_outputs_for_this_rule_source:
+ AddResourceToTarget(output, pbxp, xct)
+
+ # Do we have a message to print when this rule runs?
+ message = rule.get('message')
+ if message:
+ message = gyp.common.EncodePOSIXShellArgument(message)
+ message = ExpandXcodeVariables(message, rule_input_dict)
+ messages.append(message)
+
+ # Turn the list into a string that can be passed to a shell.
+ action_string = gyp.common.EncodePOSIXShellList(rule['action'])
+
+ action = ExpandXcodeVariables(action_string, rule_input_dict)
+ actions.append(action)
+
+ if len(concrete_outputs_all) > 0:
+ # TODO(mark): There's a possibilty for collision here. Consider
+ # target "t" rule "A_r" and target "t_A" rule "r".
+ makefile_name = '%s_%s.make' % (target_name, rule['rule_name'])
+ makefile_path = os.path.join(xcode_projects[build_file].path,
+ makefile_name)
+ # TODO(mark): try/close? Write to a temporary file and swap it only
+ # if it's got changes?
+ makefile = open(makefile_path, 'wb')
+
+ # make will build the first target in the makefile by default. By
+ # convention, it's called "all". List all (or at least one)
+ # concrete output for each rule source as a prerequisite of the "all"
+ # target.
+ makefile.write('all: \\\n')
+ for concrete_output_index in \
+ xrange(0, len(concrete_outputs_by_rule_source)):
+ # Only list the first (index [0]) concrete output of each input
+ # in the "all" target. Otherwise, a parallel make (-j > 1) would
+ # attempt to process each input multiple times simultaneously.
+ # Otherwise, "all" could just contain the entire list of
+ # concrete_outputs_all.
+ concrete_output = \
+ concrete_outputs_by_rule_source[concrete_output_index][0]
+ if concrete_output_index == len(concrete_outputs_by_rule_source) - 1:
+ eol = ''
+ else:
+ eol = ' \\'
+ makefile.write(' %s%s\n' % (concrete_output, eol))
+
+ for (rule_source, concrete_outputs, message, action) in \
+ zip(rule['rule_sources'], concrete_outputs_by_rule_source,
+ messages, actions):
+ makefile.write('\n')
+
+ # Add a rule that declares it can build each concrete output of a
+ # rule source. Collect the names of the directories that are
+ # required.
+ concrete_output_dirs = []
+ for concrete_output_index in xrange(0, len(concrete_outputs)):
+ concrete_output = concrete_outputs[concrete_output_index]
+ if concrete_output_index == 0:
+ bol = ''
+ else:
+ bol = ' '
+ makefile.write('%s%s \\\n' % (bol, concrete_output))
+
+ concrete_output_dir = posixpath.dirname(concrete_output)
+ if (concrete_output_dir and
+ concrete_output_dir not in concrete_output_dirs):
+ concrete_output_dirs.append(concrete_output_dir)
+
+ makefile.write(' : \\\n')
+
+ # The prerequisites for this rule are the rule source itself and
+ # the set of additional rule inputs, if any.
+ prerequisites = [rule_source]
+ prerequisites.extend(rule.get('inputs', []))
+ for prerequisite_index in xrange(0, len(prerequisites)):
+ prerequisite = prerequisites[prerequisite_index]
+ if prerequisite_index == len(prerequisites) - 1:
+ eol = ''
+ else:
+ eol = ' \\'
+ makefile.write(' %s%s\n' % (prerequisite, eol))
+
+ # Make sure that output directories exist before executing the rule
+ # action.
+ if len(concrete_output_dirs) > 0:
+ makefile.write('\t@mkdir -p "%s"\n' %
+ '" "'.join(concrete_output_dirs))
+
+ # The rule message and action have already had the necessary variable
+ # substitutions performed.
+ if message:
+ # Mark it with note: so Xcode picks it up in build output.
+ makefile.write('\t@echo note: %s\n' % message)
+ makefile.write('\t%s\n' % action)
+
+ makefile.close()
+
+ # It might be nice to ensure that needed output directories exist
+ # here rather than in each target in the Makefile, but that wouldn't
+ # work if there ever was a concrete output that had an input-dependent
+ # variable anywhere other than in the leaf position.
+
+ # Don't declare any inputPaths or outputPaths. If they're present,
+ # Xcode will provide a slight optimization by only running the script
+ # phase if any output is missing or outdated relative to any input.
+ # Unfortunately, it will also assume that all outputs are touched by
+ # the script, and if the outputs serve as files in a compilation
+ # phase, they will be unconditionally rebuilt. Since make might not
+ # rebuild everything that could be declared here as an output, this
+ # extra compilation activity is unnecessary. With inputPaths and
+ # outputPaths not supplied, make will always be called, but it knows
+ # enough to not do anything when everything is up-to-date.
+
+ # To help speed things up, pass -j COUNT to make so it does some work
+ # in parallel. Don't use ncpus because Xcode will build ncpus targets
+ # in parallel and if each target happens to have a rules step, there
+ # would be ncpus^2 things going. With a machine that has 2 quad-core
+ # Xeons, a build can quickly run out of processes based on
+ # scheduling/other tasks, and randomly failing builds are no good.
+ script = \
+"""JOB_COUNT="$(/usr/sbin/sysctl -n hw.ncpu)"
+if [ "${JOB_COUNT}" -gt 4 ]; then
+ JOB_COUNT=4
+fi
+exec "${DEVELOPER_BIN_DIR}/make" -f "${PROJECT_FILE_PATH}/%s" -j "${JOB_COUNT}"
+exit 1
+""" % makefile_name
+ ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
+ 'name': 'Rule "' + rule['rule_name'] + '"',
+ 'shellScript': script,
+ 'showEnvVarsInLog': 0,
+ })
+
+ if support_xct:
+ support_xct.AppendProperty('buildPhases', ssbp)
+ else:
+ # TODO(mark): this assumes too much knowledge of the internals of
+ # xcodeproj_file; some of these smarts should move into xcodeproj_file
+ # itself.
+ xct._properties['buildPhases'].insert(prebuild_index, ssbp)
+ prebuild_index = prebuild_index + 1
+
+ # Extra rule inputs also go into the project file. Concrete outputs were
+ # already added when they were computed.
+ groups = ['inputs', 'inputs_excluded']
+ if skip_excluded_files:
+ groups = [x for x in groups if not x.endswith('_excluded')]
+ for group in groups:
+ for item in rule.get(group, []):
+ pbxp.AddOrGetFileInRootGroup(item)
+
+ # Add "sources".
+ for source in spec.get('sources', []):
+ (source_root, source_extension) = posixpath.splitext(source)
+ if source_extension[1:] not in rules_by_ext:
+ # AddSourceToTarget will add the file to a root group if it's not
+ # already there.
+ AddSourceToTarget(source, pbxp, xct)
+ else:
+ pbxp.AddOrGetFileInRootGroup(source)
+
+ # Add "mac_bundle_resources", "mac_framework_headers", and
+ # "mac_framework_private_headers" if it's a bundle of any type.
+ if is_bundle:
+ for resource in tgt_mac_bundle_resources:
+ (resource_root, resource_extension) = posixpath.splitext(resource)
+ if resource_extension[1:] not in rules_by_ext:
+ AddResourceToTarget(resource, pbxp, xct)
+ else:
+ pbxp.AddOrGetFileInRootGroup(resource)
+
+ for header in spec.get('mac_framework_headers', []):
+ AddHeaderToTarget(header, pbxp, xct, True)
+
+ for header in spec.get('mac_framework_private_headers', []):
+ AddHeaderToTarget(header, pbxp, xct, False)
+
+ # Add "copies".
+ for copy_group in spec.get('copies', []):
+ pbxcp = gyp.xcodeproj_file.PBXCopyFilesBuildPhase({
+ 'name': 'Copy to ' + copy_group['destination']
+ },
+ parent=xct)
+ dest = copy_group['destination']
+ if dest[0] not in ('/', '$'):
+ # Relative paths are relative to $(SRCROOT).
+ dest = '$(SRCROOT)/' + dest
+ pbxcp.SetDestination(dest)
+
+ # TODO(mark): The usual comment about this knowing too much about
+ # gyp.xcodeproj_file internals applies.
+ xct._properties['buildPhases'].insert(prebuild_index, pbxcp)
+
+ for file in copy_group['files']:
+ pbxcp.AddFile(file)
+
+ # Excluded files can also go into the project file.
+ if not skip_excluded_files:
+ for key in ['sources', 'mac_bundle_resources', 'mac_framework_headers',
+ 'mac_framework_private_headers']:
+ excluded_key = key + '_excluded'
+ for item in spec.get(excluded_key, []):
+ pbxp.AddOrGetFileInRootGroup(item)
+
+ # So can "inputs" and "outputs" sections of "actions" groups.
+ groups = ['inputs', 'inputs_excluded', 'outputs', 'outputs_excluded']
+ if skip_excluded_files:
+ groups = [x for x in groups if not x.endswith('_excluded')]
+ for action in spec.get('actions', []):
+ for group in groups:
+ for item in action.get(group, []):
+ # Exclude anything in BUILT_PRODUCTS_DIR. They're products, not
+ # sources.
+ if not item.startswith('$(BUILT_PRODUCTS_DIR)/'):
+ pbxp.AddOrGetFileInRootGroup(item)
+
+ for postbuild in spec.get('postbuilds', []):
+ action_string_sh = gyp.common.EncodePOSIXShellList(postbuild['action'])
+ script = 'exec ' + action_string_sh + '\nexit 1\n'
+
+ # Make the postbuild step depend on the output of ld or ar from this
+ # target. Apparently putting the script step after the link step isn't
+ # sufficient to ensure proper ordering in all cases. With an input
+ # declared but no outputs, the script step should run every time, as
+ # desired.
+ ssbp = gyp.xcodeproj_file.PBXShellScriptBuildPhase({
+ 'inputPaths': ['$(BUILT_PRODUCTS_DIR)/$(EXECUTABLE_PATH)'],
+ 'name': 'Postbuild "' + postbuild['postbuild_name'] + '"',
+ 'shellScript': script,
+ 'showEnvVarsInLog': 0,
+ })
+ xct.AppendProperty('buildPhases', ssbp)
+
+ # Add dependencies before libraries, because adding a dependency may imply
+ # adding a library. It's preferable to keep dependencies listed first
+ # during a link phase so that they can override symbols that would
+ # otherwise be provided by libraries, which will usually include system
+ # libraries. On some systems, ld is finicky and even requires the
+ # libraries to be ordered in such a way that unresolved symbols in
+ # earlier-listed libraries may only be resolved by later-listed libraries.
+ # The Mac linker doesn't work that way, but other platforms do, and so
+ # their linker invocations need to be constructed in this way. There's
+ # no compelling reason for Xcode's linker invocations to differ.
+
+ if 'dependencies' in spec:
+ for dependency in spec['dependencies']:
+ xct.AddDependency(xcode_targets[dependency])
+ # The support project also gets the dependencies (in case they are
+ # needed for the actions/rules to work).
+ if support_xct:
+ support_xct.AddDependency(xcode_targets[dependency])
+
+ if 'libraries' in spec:
+ for library in spec['libraries']:
+ xct.FrameworksPhase().AddFile(library)
+ # Add the library's directory to LIBRARY_SEARCH_PATHS if necessary.
+ # I wish Xcode handled this automatically.
+ library_dir = posixpath.dirname(library)
+ if library_dir not in xcode_standard_library_dirs and (
+ not xct.HasBuildSetting(_library_search_paths_var) or
+ library_dir not in xct.GetBuildSetting(_library_search_paths_var)):
+ xct.AppendBuildSetting(_library_search_paths_var, library_dir)
+
+ for configuration_name in configuration_names:
+ configuration = spec['configurations'][configuration_name]
+ xcbc = xct.ConfigurationNamed(configuration_name)
+ for include_dir in configuration.get('mac_framework_dirs', []):
+ xcbc.AppendBuildSetting('FRAMEWORK_SEARCH_PATHS', include_dir)
+ for include_dir in configuration.get('include_dirs', []):
+ xcbc.AppendBuildSetting('HEADER_SEARCH_PATHS', include_dir)
+ if 'defines' in configuration:
+ for define in configuration['defines']:
+ set_define = EscapeXCodeArgument(define)
+ xcbc.AppendBuildSetting('GCC_PREPROCESSOR_DEFINITIONS', set_define)
+ if 'xcode_settings' in configuration:
+ for xck, xcv in configuration['xcode_settings'].iteritems():
+ xcbc.SetBuildSetting(xck, xcv)
+ if 'xcode_config_file' in configuration:
+ config_ref = pbxp.AddOrGetFileInRootGroup(
+ configuration['xcode_config_file'])
+ xcbc.SetBaseConfiguration(config_ref)
+
+ build_files = []
+ for build_file, build_file_dict in data.iteritems():
+ if build_file.endswith('.gyp'):
+ build_files.append(build_file)
+
+ for build_file in build_files:
+ xcode_projects[build_file].Finalize1(xcode_targets, serialize_all_tests)
+
+ for build_file in build_files:
+ xcode_projects[build_file].Finalize2(xcode_targets,
+ xcode_target_to_target_dict)
+
+ for build_file in build_files:
+ xcode_projects[build_file].Write()
diff --git a/Source/ThirdParty/gyp/pylib/gyp/input.py b/Source/ThirdParty/gyp/pylib/gyp/input.py
new file mode 100644
index 000000000..54e246654
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/input.py
@@ -0,0 +1,2250 @@
+#!/usr/bin/python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from compiler.ast import Const
+from compiler.ast import Dict
+from compiler.ast import Discard
+from compiler.ast import List
+from compiler.ast import Module
+from compiler.ast import Node
+from compiler.ast import Stmt
+import compiler
+import copy
+import gyp.common
+import optparse
+import os.path
+import re
+import shlex
+import subprocess
+import sys
+
+
+# A list of types that are treated as linkable.
+linkable_types = ['executable', 'shared_library', 'loadable_module']
+
+# A list of sections that contain links to other targets.
+dependency_sections = ['dependencies', 'export_dependent_settings']
+
+# base_path_sections is a list of sections defined by GYP that contain
+# pathnames. The generators can provide more keys, the two lists are merged
+# into path_sections, but you should call IsPathSection instead of using either
+# list directly.
+base_path_sections = [
+ 'destination',
+ 'files',
+ 'include_dirs',
+ 'inputs',
+ 'libraries',
+ 'outputs',
+ 'sources',
+]
+path_sections = []
+
+
+def IsPathSection(section):
+ # If section ends in one of these characters, it's applied to a section
+ # without the trailing characters. '/' is notably absent from this list,
+ # because there's no way for a regular expression to be treated as a path.
+ while section[-1:] in ('=', '+', '?', '!'):
+ section = section[0:-1]
+
+ if section in path_sections or \
+ section.endswith('_dir') or section.endswith('_dirs') or \
+ section.endswith('_file') or section.endswith('_files') or \
+ section.endswith('_path') or section.endswith('_paths'):
+ return True
+ return False
+
+
+# base_non_configuraiton_keys is a list of key names that belong in the target
+# itself and should not be propagated into its configurations. It is merged
+# with a list that can come from the generator to
+# create non_configuration_keys.
+base_non_configuration_keys = [
+ # Sections that must exist inside targets and not configurations.
+ 'actions',
+ 'configurations',
+ 'copies',
+ 'default_configuration',
+ 'dependencies',
+ 'dependencies_original',
+ 'link_languages',
+ 'libraries',
+ 'postbuilds',
+ 'product_dir',
+ 'product_extension',
+ 'product_name',
+ 'product_prefix',
+ 'rules',
+ 'run_as',
+ 'sources',
+ 'suppress_wildcard',
+ 'target_name',
+ 'toolset',
+ 'toolsets',
+ 'type',
+ 'variants',
+
+ # Sections that can be found inside targets or configurations, but that
+ # should not be propagated from targets into their configurations.
+ 'variables',
+]
+non_configuration_keys = []
+
+# Keys that do not belong inside a configuration dictionary.
+invalid_configuration_keys = [
+ 'actions',
+ 'all_dependent_settings',
+ 'configurations',
+ 'dependencies',
+ 'direct_dependent_settings',
+ 'libraries',
+ 'link_settings',
+ 'sources',
+ 'target_name',
+ 'type',
+]
+
+# Controls how the generator want the build file paths.
+absolute_build_file_paths = False
+
+# Controls whether or not the generator supports multiple toolsets.
+multiple_toolsets = False
+
+
+def GetIncludedBuildFiles(build_file_path, aux_data, included=None):
+ """Return a list of all build files included into build_file_path.
+
+ The returned list will contain build_file_path as well as all other files
+ that it included, either directly or indirectly. Note that the list may
+ contain files that were included into a conditional section that evaluated
+ to false and was not merged into build_file_path's dict.
+
+ aux_data is a dict containing a key for each build file or included build
+ file. Those keys provide access to dicts whose "included" keys contain
+ lists of all other files included by the build file.
+
+ included should be left at its default None value by external callers. It
+ is used for recursion.
+
+ The returned list will not contain any duplicate entries. Each build file
+ in the list will be relative to the current directory.
+ """
+
+ if included == None:
+ included = []
+
+ if build_file_path in included:
+ return included
+
+ included.append(build_file_path)
+
+ for included_build_file in aux_data[build_file_path].get('included', []):
+ GetIncludedBuildFiles(included_build_file, aux_data, included)
+
+ return included
+
+
+def CheckedEval(file_contents):
+ """Return the eval of a gyp file.
+
+ The gyp file is restricted to dictionaries and lists only, and
+ repeated keys are not allowed.
+
+ Note that this is slower than eval() is.
+ """
+
+ ast = compiler.parse(file_contents)
+ assert isinstance(ast, Module)
+ c1 = ast.getChildren()
+ assert c1[0] is None
+ assert isinstance(c1[1], Stmt)
+ c2 = c1[1].getChildren()
+ assert isinstance(c2[0], Discard)
+ c3 = c2[0].getChildren()
+ assert len(c3) == 1
+ return CheckNode(c3[0], [])
+
+
+def CheckNode(node, keypath):
+ if isinstance(node, Dict):
+ c = node.getChildren()
+ dict = {}
+ for n in range(0, len(c), 2):
+ assert isinstance(c[n], Const)
+ key = c[n].getChildren()[0]
+ if key in dict:
+ raise KeyError, "Key '" + key + "' repeated at level " + \
+ repr(len(keypath) + 1) + " with key path '" + \
+ '.'.join(keypath) + "'"
+ kp = list(keypath) # Make a copy of the list for descending this node.
+ kp.append(key)
+ dict[key] = CheckNode(c[n + 1], kp)
+ return dict
+ elif isinstance(node, List):
+ c = node.getChildren()
+ children = []
+ for index, child in enumerate(c):
+ kp = list(keypath) # Copy list.
+ kp.append(repr(index))
+ children.append(CheckNode(child, kp))
+ return children
+ elif isinstance(node, Const):
+ return node.getChildren()[0]
+ else:
+ raise TypeError, "Unknown AST node at key path '" + '.'.join(keypath) + \
+ "': " + repr(node)
+
+
+def LoadOneBuildFile(build_file_path, data, aux_data, variables, includes,
+ is_target, check):
+ if build_file_path in data:
+ return data[build_file_path]
+
+ if os.path.exists(build_file_path):
+ build_file_contents = open(build_file_path).read()
+ else:
+ raise Exception("%s not found (cwd: %s)" % (build_file_path, os.getcwd()))
+
+ build_file_data = None
+ try:
+ if check:
+ build_file_data = CheckedEval(build_file_contents)
+ else:
+ build_file_data = eval(build_file_contents, {'__builtins__': None},
+ None)
+ except SyntaxError, e:
+ e.filename = build_file_path
+ raise
+ except Exception, e:
+ gyp.common.ExceptionAppend(e, 'while reading ' + build_file_path)
+ raise
+
+ data[build_file_path] = build_file_data
+ aux_data[build_file_path] = {}
+
+ # Scan for includes and merge them in.
+ try:
+ if is_target:
+ LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
+ aux_data, variables, includes, check)
+ else:
+ LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
+ aux_data, variables, None, check)
+ except Exception, e:
+ gyp.common.ExceptionAppend(e,
+ 'while reading includes of ' + build_file_path)
+ raise
+
+ return build_file_data
+
+
+def LoadBuildFileIncludesIntoDict(subdict, subdict_path, data, aux_data,
+ variables, includes, check):
+ includes_list = []
+ if includes != None:
+ includes_list.extend(includes)
+ if 'includes' in subdict:
+ for include in subdict['includes']:
+ # "include" is specified relative to subdict_path, so compute the real
+ # path to include by appending the provided "include" to the directory
+ # in which subdict_path resides.
+ relative_include = \
+ os.path.normpath(os.path.join(os.path.dirname(subdict_path), include))
+ includes_list.append(relative_include)
+ # Unhook the includes list, it's no longer needed.
+ del subdict['includes']
+
+ # Merge in the included files.
+ for include in includes_list:
+ if not 'included' in aux_data[subdict_path]:
+ aux_data[subdict_path]['included'] = []
+ aux_data[subdict_path]['included'].append(include)
+
+ gyp.DebugOutput(gyp.DEBUG_INCLUDES, "Loading Included File: '%s'" % include)
+
+ MergeDicts(subdict,
+ LoadOneBuildFile(include, data, aux_data, variables, None,
+ False, check),
+ subdict_path, include)
+
+ # Recurse into subdictionaries.
+ for k, v in subdict.iteritems():
+ if v.__class__ == dict:
+ LoadBuildFileIncludesIntoDict(v, subdict_path, data, aux_data, variables,
+ None, check)
+ elif v.__class__ == list:
+ LoadBuildFileIncludesIntoList(v, subdict_path, data, aux_data, variables,
+ check)
+
+
+# This recurses into lists so that it can look for dicts.
+def LoadBuildFileIncludesIntoList(sublist, sublist_path, data, aux_data,
+ variables, check):
+ for item in sublist:
+ if item.__class__ == dict:
+ LoadBuildFileIncludesIntoDict(item, sublist_path, data, aux_data,
+ variables, None, check)
+ elif item.__class__ == list:
+ LoadBuildFileIncludesIntoList(item, sublist_path, data, aux_data,
+ variables, check)
+
+# Processes toolsets in all the targets. This recurses into condition entries
+# since they can contain toolsets as well.
+def ProcessToolsetsInDict(data):
+ if 'targets' in data:
+ target_list = data['targets']
+ new_target_list = []
+ for target in target_list:
+ global multiple_toolsets
+ if multiple_toolsets:
+ toolsets = target.get('toolsets', ['target'])
+ else:
+ toolsets = ['target']
+ if len(toolsets) > 0:
+ # Optimization: only do copies if more than one toolset is specified.
+ for build in toolsets[1:]:
+ new_target = copy.deepcopy(target)
+ new_target['toolset'] = build
+ new_target_list.append(new_target)
+ target['toolset'] = toolsets[0]
+ new_target_list.append(target)
+ data['targets'] = new_target_list
+ if 'conditions' in data:
+ for condition in data['conditions']:
+ if isinstance(condition, list):
+ for condition_dict in condition[1:]:
+ ProcessToolsetsInDict(condition_dict)
+
+
+# TODO(mark): I don't love this name. It just means that it's going to load
+# a build file that contains targets and is expected to provide a targets dict
+# that contains the targets...
+def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
+ depth, check):
+ global absolute_build_file_paths
+
+ # If depth is set, predefine the DEPTH variable to be a relative path from
+ # this build file's directory to the directory identified by depth.
+ if depth:
+ # TODO(dglazkov) The backslash/forward-slash replacement at the end is a
+ # temporary measure. This should really be addressed by keeping all paths
+ # in POSIX until actual project generation.
+ d = gyp.common.RelativePath(depth, os.path.dirname(build_file_path))
+ if d == '':
+ variables['DEPTH'] = '.'
+ else:
+ variables['DEPTH'] = d.replace('\\', '/')
+
+ # If the generator needs absolue paths, then do so.
+ if absolute_build_file_paths:
+ build_file_path = os.path.abspath(build_file_path)
+
+ if build_file_path in data['target_build_files']:
+ # Already loaded.
+ return
+ data['target_build_files'].add(build_file_path)
+
+ gyp.DebugOutput(gyp.DEBUG_INCLUDES,
+ "Loading Target Build File '%s'" % build_file_path)
+
+ build_file_data = LoadOneBuildFile(build_file_path, data, aux_data, variables,
+ includes, True, check)
+
+ # Store DEPTH for later use in generators.
+ build_file_data['_DEPTH'] = depth
+
+ # Set up the included_files key indicating which .gyp files contributed to
+ # this target dict.
+ if 'included_files' in build_file_data:
+ raise KeyError, build_file_path + ' must not contain included_files key'
+
+ included = GetIncludedBuildFiles(build_file_path, aux_data)
+ build_file_data['included_files'] = []
+ for included_file in included:
+ # included_file is relative to the current directory, but it needs to
+ # be made relative to build_file_path's directory.
+ included_relative = \
+ gyp.common.RelativePath(included_file,
+ os.path.dirname(build_file_path))
+ build_file_data['included_files'].append(included_relative)
+
+ ProcessToolsetsInDict(build_file_data)
+
+ # Apply "pre"/"early" variable expansions and condition evaluations.
+ ProcessVariablesAndConditionsInDict(build_file_data, False, variables,
+ build_file_path)
+
+ # Look at each project's target_defaults dict, and merge settings into
+ # targets.
+ if 'target_defaults' in build_file_data:
+ index = 0
+ if 'targets' in build_file_data:
+ while index < len(build_file_data['targets']):
+ # This procedure needs to give the impression that target_defaults is
+ # used as defaults, and the individual targets inherit from that.
+ # The individual targets need to be merged into the defaults. Make
+ # a deep copy of the defaults for each target, merge the target dict
+ # as found in the input file into that copy, and then hook up the
+ # copy with the target-specific data merged into it as the replacement
+ # target dict.
+ old_target_dict = build_file_data['targets'][index]
+ new_target_dict = copy.deepcopy(build_file_data['target_defaults'])
+ MergeDicts(new_target_dict, old_target_dict,
+ build_file_path, build_file_path)
+ build_file_data['targets'][index] = new_target_dict
+ index = index + 1
+ else:
+ raise Exception, \
+ "Unable to find targets in build file %s" % build_file_path
+
+ # No longer needed.
+ del build_file_data['target_defaults']
+
+ # Look for dependencies. This means that dependency resolution occurs
+ # after "pre" conditionals and variable expansion, but before "post" -
+ # in other words, you can't put a "dependencies" section inside a "post"
+ # conditional within a target.
+
+ if 'targets' in build_file_data:
+ for target_dict in build_file_data['targets']:
+ if 'dependencies' not in target_dict:
+ continue
+ for dependency in target_dict['dependencies']:
+ other_build_file = \
+ gyp.common.ResolveTarget(build_file_path, dependency, None)[0]
+ try:
+ LoadTargetBuildFile(other_build_file, data, aux_data, variables,
+ includes, depth, check)
+ except Exception, e:
+ gyp.common.ExceptionAppend(
+ e, 'while loading dependencies of %s' % build_file_path)
+ raise
+
+ return data
+
+
+# Look for the bracket that matches the first bracket seen in a
+# string, and return the start and end as a tuple. For example, if
+# the input is something like "<(foo <(bar)) blah", then it would
+# return (1, 13), indicating the entire string except for the leading
+# "<" and trailing " blah".
+def FindEnclosingBracketGroup(input):
+ brackets = { '}': '{',
+ ']': '[',
+ ')': '(', }
+ stack = []
+ count = 0
+ start = -1
+ for char in input:
+ if char in brackets.values():
+ stack.append(char)
+ if start == -1:
+ start = count
+ if char in brackets.keys():
+ try:
+ last_bracket = stack.pop()
+ except IndexError:
+ return (-1, -1)
+ if last_bracket != brackets[char]:
+ return (-1, -1)
+ if len(stack) == 0:
+ return (start, count + 1)
+ count = count + 1
+ return (-1, -1)
+
+
+canonical_int_re = re.compile('^(0|-?[1-9][0-9]*)$')
+
+
+def IsStrCanonicalInt(string):
+ """Returns True if |string| is in its canonical integer form.
+
+ The canonical form is such that str(int(string)) == string.
+ """
+ if not isinstance(string, str) or not canonical_int_re.match(string):
+ return False
+
+ return True
+
+
+early_variable_re = re.compile('(?P<replace>(?P<type><((!?@?)|\|)?)'
+ '\((?P<is_array>\s*\[?)'
+ '(?P<content>.*?)(\]?)\))')
+late_variable_re = re.compile('(?P<replace>(?P<type>>((!?@?)|\|)?)'
+ '\((?P<is_array>\s*\[?)'
+ '(?P<content>.*?)(\]?)\))')
+
+# Global cache of results from running commands so they don't have to be run
+# more then once.
+cached_command_results = {}
+
+
+def FixupPlatformCommand(cmd):
+ if sys.platform == 'win32':
+ if type(cmd) == list:
+ cmd = [re.sub('^cat ', 'type ', cmd[0])] + cmd[1:]
+ else:
+ cmd = re.sub('^cat ', 'type ', cmd)
+ return cmd
+
+
+def ExpandVariables(input, is_late, variables, build_file):
+ # Look for the pattern that gets expanded into variables
+ if not is_late:
+ variable_re = early_variable_re
+ expansion_symbol = '<'
+ else:
+ variable_re = late_variable_re
+ expansion_symbol = '>'
+
+ input_str = str(input)
+ # Do a quick scan to determine if an expensive regex search is warranted.
+ if expansion_symbol in input_str:
+ # Get the entire list of matches as a list of MatchObject instances.
+ # (using findall here would return strings instead of MatchObjects).
+ matches = [match for match in variable_re.finditer(input_str)]
+ else:
+ matches = None
+
+ output = input_str
+ if matches:
+ # Reverse the list of matches so that replacements are done right-to-left.
+ # That ensures that earlier replacements won't mess up the string in a
+ # way that causes later calls to find the earlier substituted text instead
+ # of what's intended for replacement.
+ matches.reverse()
+ for match_group in matches:
+ match = match_group.groupdict()
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+ "Matches: %s" % repr(match))
+ # match['replace'] is the substring to look for, match['type']
+ # is the character code for the replacement type (< > <! >! <| >| <@
+ # >@ <!@ >!@), match['is_array'] contains a '[' for command
+ # arrays, and match['content'] is the name of the variable (< >)
+ # or command to run (<! >!).
+
+ # run_command is true if a ! variant is used.
+ run_command = '!' in match['type']
+
+ # file_list is true if a | variant is used.
+ file_list = '|' in match['type']
+
+ # Capture these now so we can adjust them later.
+ replace_start = match_group.start('replace')
+ replace_end = match_group.end('replace')
+
+ # Find the ending paren, and re-evaluate the contained string.
+ (c_start, c_end) = FindEnclosingBracketGroup(input_str[replace_start:])
+
+ # Adjust the replacement range to match the entire command
+ # found by FindEnclosingBracketGroup (since the variable_re
+ # probably doesn't match the entire command if it contained
+ # nested variables).
+ replace_end = replace_start + c_end
+
+ # Find the "real" replacement, matching the appropriate closing
+ # paren, and adjust the replacement start and end.
+ replacement = input_str[replace_start:replace_end]
+
+ # Figure out what the contents of the variable parens are.
+ contents_start = replace_start + c_start + 1
+ contents_end = replace_end - 1
+ contents = input_str[contents_start:contents_end]
+
+ # Do filter substitution now for <|().
+ # Admittedly, this is different than the evaluation order in other
+ # contexts. However, since filtration has no chance to run on <|(),
+ # this seems like the only obvious way to give them access to filters.
+ if file_list:
+ processed_variables = copy.deepcopy(variables)
+ ProcessListFiltersInDict(contents, processed_variables)
+ # Recurse to expand variables in the contents
+ contents = ExpandVariables(contents, is_late,
+ processed_variables, build_file)
+ else:
+ # Recurse to expand variables in the contents
+ contents = ExpandVariables(contents, is_late, variables, build_file)
+
+ # Strip off leading/trailing whitespace so that variable matches are
+ # simpler below (and because they are rarely needed).
+ contents = contents.strip()
+
+ # expand_to_list is true if an @ variant is used. In that case,
+ # the expansion should result in a list. Note that the caller
+ # is to be expecting a list in return, and not all callers do
+ # because not all are working in list context. Also, for list
+ # expansions, there can be no other text besides the variable
+ # expansion in the input string.
+ expand_to_list = '@' in match['type'] and input_str == replacement
+
+ if run_command or file_list:
+ # Find the build file's directory, so commands can be run or file lists
+ # generated relative to it.
+ build_file_dir = os.path.dirname(build_file)
+ if build_file_dir == '':
+ # If build_file is just a leaf filename indicating a file in the
+ # current directory, build_file_dir might be an empty string. Set
+ # it to None to signal to subprocess.Popen that it should run the
+ # command in the current directory.
+ build_file_dir = None
+
+ # Support <|(listfile.txt ...) which generates a file
+ # containing items from a gyp list, generated at gyp time.
+ # This works around actions/rules which have more inputs than will
+ # fit on the command line.
+ if file_list:
+ if type(contents) == list:
+ contents_list = contents
+ else:
+ contents_list = contents.split(' ')
+ replacement = contents_list[0]
+ path = replacement
+ if not os.path.isabs(path):
+ path = os.path.join(build_file_dir, path)
+ f = gyp.common.WriteOnDiff(path)
+ for i in contents_list[1:]:
+ f.write('%s\n' % i)
+ f.close()
+
+ elif run_command:
+ use_shell = True
+ if match['is_array']:
+ contents = eval(contents)
+ use_shell = False
+
+ # Check for a cached value to avoid executing commands, or generating
+ # file lists more than once.
+ # TODO(http://code.google.com/p/gyp/issues/detail?id=112): It is
+ # possible that the command being invoked depends on the current
+ # directory. For that case the syntax needs to be extended so that the
+ # directory is also used in cache_key (it becomes a tuple).
+ # TODO(http://code.google.com/p/gyp/issues/detail?id=111): In theory,
+ # someone could author a set of GYP files where each time the command
+ # is invoked it produces different output by design. When the need
+ # arises, the syntax should be extended to support no caching off a
+ # command's output so it is run every time.
+ cache_key = str(contents)
+ cached_value = cached_command_results.get(cache_key, None)
+ if cached_value is None:
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+ "Executing command '%s' in directory '%s'" %
+ (contents,build_file_dir))
+
+ # Fix up command with platform specific workarounds.
+ contents = FixupPlatformCommand(contents)
+ p = subprocess.Popen(contents, shell=use_shell,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ stdin=subprocess.PIPE,
+ cwd=build_file_dir)
+
+ (p_stdout, p_stderr) = p.communicate('')
+
+ if p.wait() != 0 or p_stderr:
+ sys.stderr.write(p_stderr)
+ # Simulate check_call behavior, since check_call only exists
+ # in python 2.5 and later.
+ raise Exception("Call to '%s' returned exit status %d." %
+ (contents, p.returncode))
+ replacement = p_stdout.rstrip()
+
+ cached_command_results[cache_key] = replacement
+ else:
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+ "Had cache value for command '%s' in directory '%s'" %
+ (contents,build_file_dir))
+ replacement = cached_value
+
+ else:
+ if not contents in variables:
+ raise KeyError, 'Undefined variable ' + contents + \
+ ' in ' + build_file
+ replacement = variables[contents]
+
+ if isinstance(replacement, list):
+ for item in replacement:
+ if not isinstance(item, str) and not isinstance(item, int):
+ raise TypeError, 'Variable ' + contents + \
+ ' must expand to a string or list of strings; ' + \
+ 'list contains a ' + \
+ item.__class__.__name__
+ # Run through the list and handle variable expansions in it. Since
+ # the list is guaranteed not to contain dicts, this won't do anything
+ # with conditions sections.
+ ProcessVariablesAndConditionsInList(replacement, is_late, variables,
+ build_file)
+ elif not isinstance(replacement, str) and \
+ not isinstance(replacement, int):
+ raise TypeError, 'Variable ' + contents + \
+ ' must expand to a string or list of strings; ' + \
+ 'found a ' + replacement.__class__.__name__
+
+ if expand_to_list:
+ # Expanding in list context. It's guaranteed that there's only one
+ # replacement to do in |input_str| and that it's this replacement. See
+ # above.
+ if isinstance(replacement, list):
+ # If it's already a list, make a copy.
+ output = replacement[:]
+ else:
+ # Split it the same way sh would split arguments.
+ output = shlex.split(str(replacement))
+ else:
+ # Expanding in string context.
+ encoded_replacement = ''
+ if isinstance(replacement, list):
+ # When expanding a list into string context, turn the list items
+ # into a string in a way that will work with a subprocess call.
+ #
+ # TODO(mark): This isn't completely correct. This should
+ # call a generator-provided function that observes the
+ # proper list-to-argument quoting rules on a specific
+ # platform instead of just calling the POSIX encoding
+ # routine.
+ encoded_replacement = gyp.common.EncodePOSIXShellList(replacement)
+ else:
+ encoded_replacement = replacement
+
+ output = output[:replace_start] + str(encoded_replacement) + \
+ output[replace_end:]
+ # Prepare for the next match iteration.
+ input_str = output
+
+ # Look for more matches now that we've replaced some, to deal with
+ # expanding local variables (variables defined in the same
+ # variables block as this one).
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+ "Found output %s, recursing." % repr(output))
+ if isinstance(output, list):
+ new_output = []
+ for item in output:
+ new_output.append(ExpandVariables(item, is_late, variables, build_file))
+ output = new_output
+ else:
+ output = ExpandVariables(output, is_late, variables, build_file)
+
+ # Convert all strings that are canonically-represented integers into integers.
+ if isinstance(output, list):
+ for index in xrange(0, len(output)):
+ if IsStrCanonicalInt(output[index]):
+ output[index] = int(output[index])
+ elif IsStrCanonicalInt(output):
+ output = int(output)
+
+ gyp.DebugOutput(gyp.DEBUG_VARIABLES,
+ "Expanding %s to %s" % (repr(input), repr(output)))
+ return output
+
+
+def ProcessConditionsInDict(the_dict, is_late, variables, build_file):
+ # Process a 'conditions' or 'target_conditions' section in the_dict,
+ # depending on is_late. If is_late is False, 'conditions' is used.
+ #
+ # Each item in a conditions list consists of cond_expr, a string expression
+ # evaluated as the condition, and true_dict, a dict that will be merged into
+ # the_dict if cond_expr evaluates to true. Optionally, a third item,
+ # false_dict, may be present. false_dict is merged into the_dict if
+ # cond_expr evaluates to false.
+ #
+ # Any dict merged into the_dict will be recursively processed for nested
+ # conditionals and other expansions, also according to is_late, immediately
+ # prior to being merged.
+
+ if not is_late:
+ conditions_key = 'conditions'
+ else:
+ conditions_key = 'target_conditions'
+
+ if not conditions_key in the_dict:
+ return
+
+ conditions_list = the_dict[conditions_key]
+ # Unhook the conditions list, it's no longer needed.
+ del the_dict[conditions_key]
+
+ for condition in conditions_list:
+ if not isinstance(condition, list):
+ raise TypeError, conditions_key + ' must be a list'
+ if len(condition) != 2 and len(condition) != 3:
+ # It's possible that condition[0] won't work in which case this
+ # attempt will raise its own IndexError. That's probably fine.
+ raise IndexError, conditions_key + ' ' + condition[0] + \
+ ' must be length 2 or 3, not ' + str(len(condition))
+
+ [cond_expr, true_dict] = condition[0:2]
+ false_dict = None
+ if len(condition) == 3:
+ false_dict = condition[2]
+
+ # Do expansions on the condition itself. Since the conditon can naturally
+ # contain variable references without needing to resort to GYP expansion
+ # syntax, this is of dubious value for variables, but someone might want to
+ # use a command expansion directly inside a condition.
+ cond_expr_expanded = ExpandVariables(cond_expr, is_late, variables,
+ build_file)
+ if not isinstance(cond_expr_expanded, str) and \
+ not isinstance(cond_expr_expanded, int):
+ raise ValueError, \
+ 'Variable expansion in this context permits str and int ' + \
+ 'only, found ' + expanded.__class__.__name__
+
+ try:
+ ast_code = compile(cond_expr_expanded, '<string>', 'eval')
+
+ if eval(ast_code, {'__builtins__': None}, variables):
+ merge_dict = true_dict
+ else:
+ merge_dict = false_dict
+ except SyntaxError, e:
+ syntax_error = SyntaxError('%s while evaluating condition \'%s\' in %s '
+ 'at character %d.' %
+ (str(e.args[0]), e.text, build_file, e.offset),
+ e.filename, e.lineno, e.offset, e.text)
+ raise syntax_error
+ except NameError, e:
+ gyp.common.ExceptionAppend(e, 'while evaluating condition \'%s\' in %s' %
+ (cond_expr_expanded, build_file))
+ raise
+
+ if merge_dict != None:
+ # Expand variables and nested conditinals in the merge_dict before
+ # merging it.
+ ProcessVariablesAndConditionsInDict(merge_dict, is_late,
+ variables, build_file)
+
+ MergeDicts(the_dict, merge_dict, build_file, build_file)
+
+
+def LoadAutomaticVariablesFromDict(variables, the_dict):
+ # Any keys with plain string values in the_dict become automatic variables.
+ # The variable name is the key name with a "_" character prepended.
+ for key, value in the_dict.iteritems():
+ if isinstance(value, str) or isinstance(value, int) or \
+ isinstance(value, list):
+ variables['_' + key] = value
+
+
+def LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key):
+ # Any keys in the_dict's "variables" dict, if it has one, becomes a
+ # variable. The variable name is the key name in the "variables" dict.
+ # Variables that end with the % character are set only if they are unset in
+ # the variables dict. the_dict_key is the name of the key that accesses
+ # the_dict in the_dict's parent dict. If the_dict's parent is not a dict
+ # (it could be a list or it could be parentless because it is a root dict),
+ # the_dict_key will be None.
+ for key, value in the_dict.get('variables', {}).iteritems():
+ if not isinstance(value, str) and not isinstance(value, int) and \
+ not isinstance(value, list):
+ continue
+
+ if key.endswith('%'):
+ variable_name = key[:-1]
+ if variable_name in variables:
+ # If the variable is already set, don't set it.
+ continue
+ if the_dict_key is 'variables' and variable_name in the_dict:
+ # If the variable is set without a % in the_dict, and the_dict is a
+ # variables dict (making |variables| a varaibles sub-dict of a
+ # variables dict), use the_dict's definition.
+ value = the_dict[variable_name]
+ else:
+ variable_name = key
+
+ variables[variable_name] = value
+
+
+def ProcessVariablesAndConditionsInDict(the_dict, is_late, variables_in,
+ build_file, the_dict_key=None):
+ """Handle all variable and command expansion and conditional evaluation.
+
+ This function is the public entry point for all variable expansions and
+ conditional evaluations. The variables_in dictionary will not be modified
+ by this function.
+ """
+
+ # Make a copy of the variables_in dict that can be modified during the
+ # loading of automatics and the loading of the variables dict.
+ variables = variables_in.copy()
+ LoadAutomaticVariablesFromDict(variables, the_dict)
+
+ if 'variables' in the_dict:
+ # Make sure all the local variables are added to the variables
+ # list before we process them so that you can reference one
+ # variable from another. They will be fully expanded by recursion
+ # in ExpandVariables.
+ for key, value in the_dict['variables'].iteritems():
+ variables[key] = value
+
+ # Handle the associated variables dict first, so that any variable
+ # references within can be resolved prior to using them as variables.
+ # Pass a copy of the variables dict to avoid having it be tainted.
+ # Otherwise, it would have extra automatics added for everything that
+ # should just be an ordinary variable in this scope.
+ ProcessVariablesAndConditionsInDict(the_dict['variables'], is_late,
+ variables, build_file, 'variables')
+
+ LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
+
+ for key, value in the_dict.iteritems():
+ # Skip "variables", which was already processed if present.
+ if key != 'variables' and isinstance(value, str):
+ expanded = ExpandVariables(value, is_late, variables, build_file)
+ if not isinstance(expanded, str) and not isinstance(expanded, int):
+ raise ValueError, \
+ 'Variable expansion in this context permits str and int ' + \
+ 'only, found ' + expanded.__class__.__name__ + ' for ' + key
+ the_dict[key] = expanded
+
+ # Variable expansion may have resulted in changes to automatics. Reload.
+ # TODO(mark): Optimization: only reload if no changes were made.
+ variables = variables_in.copy()
+ LoadAutomaticVariablesFromDict(variables, the_dict)
+ LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
+
+ # Process conditions in this dict. This is done after variable expansion
+ # so that conditions may take advantage of expanded variables. For example,
+ # if the_dict contains:
+ # {'type': '<(library_type)',
+ # 'conditions': [['_type=="static_library"', { ... }]]},
+ # _type, as used in the condition, will only be set to the value of
+ # library_type if variable expansion is performed before condition
+ # processing. However, condition processing should occur prior to recursion
+ # so that variables (both automatic and "variables" dict type) may be
+ # adjusted by conditions sections, merged into the_dict, and have the
+ # intended impact on contained dicts.
+ #
+ # This arrangement means that a "conditions" section containing a "variables"
+ # section will only have those variables effective in subdicts, not in
+ # the_dict. The workaround is to put a "conditions" section within a
+ # "variables" section. For example:
+ # {'conditions': [['os=="mac"', {'variables': {'define': 'IS_MAC'}}]],
+ # 'defines': ['<(define)'],
+ # 'my_subdict': {'defines': ['<(define)']}},
+ # will not result in "IS_MAC" being appended to the "defines" list in the
+ # current scope but would result in it being appended to the "defines" list
+ # within "my_subdict". By comparison:
+ # {'variables': {'conditions': [['os=="mac"', {'define': 'IS_MAC'}]]},
+ # 'defines': ['<(define)'],
+ # 'my_subdict': {'defines': ['<(define)']}},
+ # will append "IS_MAC" to both "defines" lists.
+
+ # Evaluate conditions sections, allowing variable expansions within them
+ # as well as nested conditionals. This will process a 'conditions' or
+ # 'target_conditions' section, perform appropriate merging and recursive
+ # conditional and variable processing, and then remove the conditions section
+ # from the_dict if it is present.
+ ProcessConditionsInDict(the_dict, is_late, variables, build_file)
+
+ # Conditional processing may have resulted in changes to automatics or the
+ # variables dict. Reload.
+ variables = variables_in.copy()
+ LoadAutomaticVariablesFromDict(variables, the_dict)
+ LoadVariablesFromVariablesDict(variables, the_dict, the_dict_key)
+
+ # Recurse into child dicts, or process child lists which may result in
+ # further recursion into descendant dicts.
+ for key, value in the_dict.iteritems():
+ # Skip "variables" and string values, which were already processed if
+ # present.
+ if key == 'variables' or isinstance(value, str):
+ continue
+ if isinstance(value, dict):
+ # Pass a copy of the variables dict so that subdicts can't influence
+ # parents.
+ ProcessVariablesAndConditionsInDict(value, is_late, variables,
+ build_file, key)
+ elif isinstance(value, list):
+ # The list itself can't influence the variables dict, and
+ # ProcessVariablesAndConditionsInList will make copies of the variables
+ # dict if it needs to pass it to something that can influence it. No
+ # copy is necessary here.
+ ProcessVariablesAndConditionsInList(value, is_late, variables,
+ build_file)
+ elif not isinstance(value, int):
+ raise TypeError, 'Unknown type ' + value.__class__.__name__ + \
+ ' for ' + key
+
+
+def ProcessVariablesAndConditionsInList(the_list, is_late, variables,
+ build_file):
+ # Iterate using an index so that new values can be assigned into the_list.
+ index = 0
+ while index < len(the_list):
+ item = the_list[index]
+ if isinstance(item, dict):
+ # Make a copy of the variables dict so that it won't influence anything
+ # outside of its own scope.
+ ProcessVariablesAndConditionsInDict(item, is_late, variables, build_file)
+ elif isinstance(item, list):
+ ProcessVariablesAndConditionsInList(item, is_late, variables, build_file)
+ elif isinstance(item, str):
+ expanded = ExpandVariables(item, is_late, variables, build_file)
+ if isinstance(expanded, str) or isinstance(expanded, int):
+ the_list[index] = expanded
+ elif isinstance(expanded, list):
+ del the_list[index]
+ for expanded_item in expanded:
+ the_list.insert(index, expanded_item)
+ index = index + 1
+
+ # index now identifies the next item to examine. Continue right now
+ # without falling into the index increment below.
+ continue
+ else:
+ raise ValueError, \
+ 'Variable expansion in this context permits strings and ' + \
+ 'lists only, found ' + expanded.__class__.__name__ + ' at ' + \
+ index
+ elif not isinstance(item, int):
+ raise TypeError, 'Unknown type ' + item.__class__.__name__ + \
+ ' at index ' + index
+ index = index + 1
+
+
+def BuildTargetsDict(data):
+ """Builds a dict mapping fully-qualified target names to their target dicts.
+
+ |data| is a dict mapping loaded build files by pathname relative to the
+ current directory. Values in |data| are build file contents. For each
+ |data| value with a "targets" key, the value of the "targets" key is taken
+ as a list containing target dicts. Each target's fully-qualified name is
+ constructed from the pathname of the build file (|data| key) and its
+ "target_name" property. These fully-qualified names are used as the keys
+ in the returned dict. These keys provide access to the target dicts,
+ the dicts in the "targets" lists.
+ """
+
+ targets = {}
+ for build_file in data['target_build_files']:
+ for target in data[build_file].get('targets', []):
+ target_name = gyp.common.QualifiedTarget(build_file,
+ target['target_name'],
+ target['toolset'])
+ if target_name in targets:
+ raise KeyError, 'Duplicate target definitions for ' + target_name
+ targets[target_name] = target
+
+ return targets
+
+
+def QualifyDependencies(targets):
+ """Make dependency links fully-qualified relative to the current directory.
+
+ |targets| is a dict mapping fully-qualified target names to their target
+ dicts. For each target in this dict, keys known to contain dependency
+ links are examined, and any dependencies referenced will be rewritten
+ so that they are fully-qualified and relative to the current directory.
+ All rewritten dependencies are suitable for use as keys to |targets| or a
+ similar dict.
+ """
+
+ for target, target_dict in targets.iteritems():
+ target_build_file = gyp.common.BuildFile(target)
+ toolset = target_dict['toolset']
+ for dependency_key in dependency_sections:
+ dependencies = target_dict.get(dependency_key, [])
+ for index in xrange(0, len(dependencies)):
+ dep_file, dep_target, dep_toolset = gyp.common.ResolveTarget(
+ target_build_file, dependencies[index], toolset)
+ global multiple_toolsets
+ if not multiple_toolsets:
+ # Ignore toolset specification in the dependency if it is specified.
+ dep_toolset = toolset
+ dependency = gyp.common.QualifiedTarget(dep_file,
+ dep_target,
+ dep_toolset)
+ dependencies[index] = dependency
+
+ # Make sure anything appearing in a list other than "dependencies" also
+ # appears in the "dependencies" list.
+ if dependency_key != 'dependencies' and \
+ dependency not in target_dict['dependencies']:
+ raise KeyError, 'Found ' + dependency + ' in ' + dependency_key + \
+ ' of ' + target + ', but not in dependencies'
+
+
+def ExpandWildcardDependencies(targets, data):
+ """Expands dependencies specified as build_file:*.
+
+ For each target in |targets|, examines sections containing links to other
+ targets. If any such section contains a link of the form build_file:*, it
+ is taken as a wildcard link, and is expanded to list each target in
+ build_file. The |data| dict provides access to build file dicts.
+
+ Any target that does not wish to be included by wildcard can provide an
+ optional "suppress_wildcard" key in its target dict. When present and
+ true, a wildcard dependency link will not include such targets.
+
+ All dependency names, including the keys to |targets| and the values in each
+ dependency list, must be qualified when this function is called.
+ """
+
+ for target, target_dict in targets.iteritems():
+ toolset = target_dict['toolset']
+ target_build_file = gyp.common.BuildFile(target)
+ for dependency_key in dependency_sections:
+ dependencies = target_dict.get(dependency_key, [])
+
+ # Loop this way instead of "for dependency in" or "for index in xrange"
+ # because the dependencies list will be modified within the loop body.
+ index = 0
+ while index < len(dependencies):
+ (dependency_build_file, dependency_target, dependency_toolset) = \
+ gyp.common.ParseQualifiedTarget(dependencies[index])
+ if dependency_target != '*' and dependency_toolset != '*':
+ # Not a wildcard. Keep it moving.
+ index = index + 1
+ continue
+
+ if dependency_build_file == target_build_file:
+ # It's an error for a target to depend on all other targets in
+ # the same file, because a target cannot depend on itself.
+ raise KeyError, 'Found wildcard in ' + dependency_key + ' of ' + \
+ target + ' referring to same build file'
+
+ # Take the wildcard out and adjust the index so that the next
+ # dependency in the list will be processed the next time through the
+ # loop.
+ del dependencies[index]
+ index = index - 1
+
+ # Loop through the targets in the other build file, adding them to
+ # this target's list of dependencies in place of the removed
+ # wildcard.
+ dependency_target_dicts = data[dependency_build_file]['targets']
+ for dependency_target_dict in dependency_target_dicts:
+ if int(dependency_target_dict.get('suppress_wildcard', False)):
+ continue
+ dependency_target_name = dependency_target_dict['target_name']
+ if (dependency_target != '*' and
+ dependency_target != dependency_target_name):
+ continue
+ dependency_target_toolset = dependency_target_dict['toolset']
+ if (dependency_toolset != '*' and
+ dependency_toolset != dependency_target_toolset):
+ continue
+ dependency = gyp.common.QualifiedTarget(dependency_build_file,
+ dependency_target_name,
+ dependency_target_toolset)
+ index = index + 1
+ dependencies.insert(index, dependency)
+
+ index = index + 1
+
+
+class DependencyGraphNode(object):
+ """
+
+ Attributes:
+ ref: A reference to an object that this DependencyGraphNode represents.
+ dependencies: List of DependencyGraphNodes on which this one depends.
+ dependents: List of DependencyGraphNodes that depend on this one.
+ """
+
+ class CircularException(Exception):
+ pass
+
+ def __init__(self, ref):
+ self.ref = ref
+ self.dependencies = []
+ self.dependents = []
+
+ def FlattenToList(self):
+ # flat_list is the sorted list of dependencies - actually, the list items
+ # are the "ref" attributes of DependencyGraphNodes. Every target will
+ # appear in flat_list after all of its dependencies, and before all of its
+ # dependents.
+ flat_list = []
+
+ # in_degree_zeros is the list of DependencyGraphNodes that have no
+ # dependencies not in flat_list. Initially, it is a copy of the children
+ # of this node, because when the graph was built, nodes with no
+ # dependencies were made implicit dependents of the root node.
+ in_degree_zeros = self.dependents[:]
+
+ while in_degree_zeros:
+ # Nodes in in_degree_zeros have no dependencies not in flat_list, so they
+ # can be appended to flat_list. Take these nodes out of in_degree_zeros
+ # as work progresses, so that the next node to process from the list can
+ # always be accessed at a consistent position.
+ node = in_degree_zeros.pop(0)
+ flat_list.append(node.ref)
+
+ # Look at dependents of the node just added to flat_list. Some of them
+ # may now belong in in_degree_zeros.
+ for node_dependent in node.dependents:
+ is_in_degree_zero = True
+ for node_dependent_dependency in node_dependent.dependencies:
+ if not node_dependent_dependency.ref in flat_list:
+ # The dependent one or more dependencies not in flat_list. There
+ # will be more chances to add it to flat_list when examining
+ # it again as a dependent of those other dependencies, provided
+ # that there are no cycles.
+ is_in_degree_zero = False
+ break
+
+ if is_in_degree_zero:
+ # All of the dependent's dependencies are already in flat_list. Add
+ # it to in_degree_zeros where it will be processed in a future
+ # iteration of the outer loop.
+ in_degree_zeros.append(node_dependent)
+
+ return flat_list
+
+ def DirectDependencies(self, dependencies=None):
+ """Returns a list of just direct dependencies."""
+ if dependencies == None:
+ dependencies = []
+
+ for dependency in self.dependencies:
+ # Check for None, corresponding to the root node.
+ if dependency.ref != None and dependency.ref not in dependencies:
+ dependencies.append(dependency.ref)
+
+ return dependencies
+
+ def _AddImportedDependencies(self, targets, dependencies=None):
+ """Given a list of direct dependencies, adds indirect dependencies that
+ other dependencies have declared to export their settings.
+
+ This method does not operate on self. Rather, it operates on the list
+ of dependencies in the |dependencies| argument. For each dependency in
+ that list, if any declares that it exports the settings of one of its
+ own dependencies, those dependencies whose settings are "passed through"
+ are added to the list. As new items are added to the list, they too will
+ be processed, so it is possible to import settings through multiple levels
+ of dependencies.
+
+ This method is not terribly useful on its own, it depends on being
+ "primed" with a list of direct dependencies such as one provided by
+ DirectDependencies. DirectAndImportedDependencies is intended to be the
+ public entry point.
+ """
+
+ if dependencies == None:
+ dependencies = []
+
+ index = 0
+ while index < len(dependencies):
+ dependency = dependencies[index]
+ dependency_dict = targets[dependency]
+ # Add any dependencies whose settings should be imported to the list
+ # if not already present. Newly-added items will be checked for
+ # their own imports when the list iteration reaches them.
+ # Rather than simply appending new items, insert them after the
+ # dependency that exported them. This is done to more closely match
+ # the depth-first method used by DeepDependencies.
+ add_index = 1
+ for imported_dependency in \
+ dependency_dict.get('export_dependent_settings', []):
+ if imported_dependency not in dependencies:
+ dependencies.insert(index + add_index, imported_dependency)
+ add_index = add_index + 1
+ index = index + 1
+
+ return dependencies
+
+ def DirectAndImportedDependencies(self, targets, dependencies=None):
+ """Returns a list of a target's direct dependencies and all indirect
+ dependencies that a dependency has advertised settings should be exported
+ through the dependency for.
+ """
+
+ dependencies = self.DirectDependencies(dependencies)
+ return self._AddImportedDependencies(targets, dependencies)
+
+ def DeepDependencies(self, dependencies=None):
+ """Returns a list of all of a target's dependencies, recursively."""
+ if dependencies == None:
+ dependencies = []
+
+ for dependency in self.dependencies:
+ # Check for None, corresponding to the root node.
+ if dependency.ref != None and dependency.ref not in dependencies:
+ dependencies.append(dependency.ref)
+ dependency.DeepDependencies(dependencies)
+
+ return dependencies
+
+ def LinkDependencies(self, targets, dependencies=None, initial=True):
+ """Returns a list of dependency targets that are linked into this target.
+
+ This function has a split personality, depending on the setting of
+ |initial|. Outside callers should always leave |initial| at its default
+ setting.
+
+ When adding a target to the list of dependencies, this function will
+ recurse into itself with |initial| set to False, to collect depenedencies
+ that are linked into the linkable target for which the list is being built.
+ """
+ if dependencies == None:
+ dependencies = []
+
+ # Check for None, corresponding to the root node.
+ if self.ref == None:
+ return dependencies
+
+ # It's kind of sucky that |targets| has to be passed into this function,
+ # but that's presently the easiest way to access the target dicts so that
+ # this function can find target types.
+
+ if not 'target_name' in targets[self.ref]:
+ raise Exception("Missing 'target_name' field in target.")
+
+ try:
+ target_type = targets[self.ref]['type']
+ except KeyError, e:
+ raise Exception("Missing 'type' field in target %s" %
+ targets[self.ref]['target_name'])
+
+ is_linkable = target_type in linkable_types
+
+ if initial and not is_linkable:
+ # If this is the first target being examined and it's not linkable,
+ # return an empty list of link dependencies, because the link
+ # dependencies are intended to apply to the target itself (initial is
+ # True) and this target won't be linked.
+ return dependencies
+
+ # Executables and loadable modules are already fully and finally linked.
+ # Nothing else can be a link dependency of them, there can only be
+ # dependencies in the sense that a dependent target might run an
+ # executable or load the loadable_module.
+ if not initial and target_type in ('executable', 'loadable_module'):
+ return dependencies
+
+ # The target is linkable, add it to the list of link dependencies.
+ if self.ref not in dependencies:
+ if target_type != 'none':
+ # Special case: "none" type targets don't produce any linkable products
+ # and shouldn't be exposed as link dependencies, although dependencies
+ # of "none" type targets may still be link dependencies.
+ dependencies.append(self.ref)
+ if initial or not is_linkable:
+ # If this is a subsequent target and it's linkable, don't look any
+ # further for linkable dependencies, as they'll already be linked into
+ # this target linkable. Always look at dependencies of the initial
+ # target, and always look at dependencies of non-linkables.
+ for dependency in self.dependencies:
+ dependency.LinkDependencies(targets, dependencies, False)
+
+ return dependencies
+
+
+def BuildDependencyList(targets):
+ # Create a DependencyGraphNode for each target. Put it into a dict for easy
+ # access.
+ dependency_nodes = {}
+ for target, spec in targets.iteritems():
+ if not target in dependency_nodes:
+ dependency_nodes[target] = DependencyGraphNode(target)
+
+ # Set up the dependency links. Targets that have no dependencies are treated
+ # as dependent on root_node.
+ root_node = DependencyGraphNode(None)
+ for target, spec in targets.iteritems():
+ target_node = dependency_nodes[target]
+ target_build_file = gyp.common.BuildFile(target)
+ if not 'dependencies' in spec or len(spec['dependencies']) == 0:
+ target_node.dependencies = [root_node]
+ root_node.dependents.append(target_node)
+ else:
+ dependencies = spec['dependencies']
+ for index in xrange(0, len(dependencies)):
+ try:
+ dependency = dependencies[index]
+ dependency_node = dependency_nodes[dependency]
+ target_node.dependencies.append(dependency_node)
+ dependency_node.dependents.append(target_node)
+ except KeyError, e:
+ gyp.common.ExceptionAppend(e,
+ 'while trying to load target %s' % target)
+ raise
+
+ flat_list = root_node.FlattenToList()
+
+ # If there's anything left unvisited, there must be a circular dependency
+ # (cycle). If you need to figure out what's wrong, look for elements of
+ # targets that are not in flat_list.
+ if len(flat_list) != len(targets):
+ raise DependencyGraphNode.CircularException, \
+ 'Some targets not reachable, cycle in dependency graph detected'
+
+ return [dependency_nodes, flat_list]
+
+
+def VerifyNoGYPFileCircularDependencies(targets):
+ # Create a DependencyGraphNode for each gyp file containing a target. Put
+ # it into a dict for easy access.
+ dependency_nodes = {}
+ for target in targets.iterkeys():
+ build_file = gyp.common.BuildFile(target)
+ if not build_file in dependency_nodes:
+ dependency_nodes[build_file] = DependencyGraphNode(build_file)
+
+ # Set up the dependency links.
+ for target, spec in targets.iteritems():
+ build_file = gyp.common.BuildFile(target)
+ build_file_node = dependency_nodes[build_file]
+ target_dependencies = spec.get('dependencies', [])
+ for dependency in target_dependencies:
+ try:
+ dependency_build_file = gyp.common.BuildFile(dependency)
+ if dependency_build_file == build_file:
+ # A .gyp file is allowed to refer back to itself.
+ continue
+ dependency_node = dependency_nodes[dependency_build_file]
+ if dependency_node not in build_file_node.dependencies:
+ build_file_node.dependencies.append(dependency_node)
+ dependency_node.dependents.append(build_file_node)
+ except KeyError, e:
+ gyp.common.ExceptionAppend(
+ e, 'while computing dependencies of .gyp file %s' % build_file)
+ raise
+
+ # Files that have no dependencies are treated as dependent on root_node.
+ root_node = DependencyGraphNode(None)
+ for build_file_node in dependency_nodes.itervalues():
+ if len(build_file_node.dependencies) == 0:
+ build_file_node.dependencies.append(root_node)
+ root_node.dependents.append(build_file_node)
+
+ flat_list = root_node.FlattenToList()
+
+ # If there's anything left unvisited, there must be a circular dependency
+ # (cycle).
+ if len(flat_list) != len(dependency_nodes):
+ bad_files = []
+ for file in dependency_nodes.iterkeys():
+ if not file in flat_list:
+ bad_files.append(file)
+ raise DependencyGraphNode.CircularException, \
+ 'Some files not reachable, cycle in .gyp file dependency graph ' + \
+ 'detected involving some or all of: ' + \
+ ' '.join(bad_files)
+
+
+def DoDependentSettings(key, flat_list, targets, dependency_nodes):
+ # key should be one of all_dependent_settings, direct_dependent_settings,
+ # or link_settings.
+
+ for target in flat_list:
+ target_dict = targets[target]
+ build_file = gyp.common.BuildFile(target)
+
+ if key == 'all_dependent_settings':
+ dependencies = dependency_nodes[target].DeepDependencies()
+ elif key == 'direct_dependent_settings':
+ dependencies = \
+ dependency_nodes[target].DirectAndImportedDependencies(targets)
+ elif key == 'link_settings':
+ dependencies = dependency_nodes[target].LinkDependencies(targets)
+ else:
+ raise KeyError, "DoDependentSettings doesn't know how to determine " + \
+ 'dependencies for ' + key
+
+ for dependency in dependencies:
+ dependency_dict = targets[dependency]
+ if not key in dependency_dict:
+ continue
+ dependency_build_file = gyp.common.BuildFile(dependency)
+ MergeDicts(target_dict, dependency_dict[key],
+ build_file, dependency_build_file)
+
+
+def AdjustStaticLibraryDependencies(flat_list, targets, dependency_nodes):
+ # Recompute target "dependencies" properties. For each static library
+ # target, remove "dependencies" entries referring to other static libraries,
+ # unless the dependency has the "hard_dependency" attribute set. For each
+ # linkable target, add a "dependencies" entry referring to all of the
+ # target's computed list of link dependencies (including static libraries
+ # if no such entry is already present.
+ for target in flat_list:
+ target_dict = targets[target]
+ target_type = target_dict['type']
+
+ if target_type == 'static_library':
+ if not 'dependencies' in target_dict:
+ continue
+
+ target_dict['dependencies_original'] = target_dict.get(
+ 'dependencies', [])[:]
+
+ index = 0
+ while index < len(target_dict['dependencies']):
+ dependency = target_dict['dependencies'][index]
+ dependency_dict = targets[dependency]
+ if dependency_dict['type'] == 'static_library' and \
+ (not 'hard_dependency' in dependency_dict or \
+ not dependency_dict['hard_dependency']):
+ # A static library should not depend on another static library unless
+ # the dependency relationship is "hard," which should only be done
+ # when a dependent relies on some side effect other than just the
+ # build product, like a rule or action output. Take the dependency
+ # out of the list, and don't increment index because the next
+ # dependency to analyze will shift into the index formerly occupied
+ # by the one being removed.
+ del target_dict['dependencies'][index]
+ else:
+ index = index + 1
+
+ # If the dependencies list is empty, it's not needed, so unhook it.
+ if len(target_dict['dependencies']) == 0:
+ del target_dict['dependencies']
+
+ elif target_type in linkable_types:
+ # Get a list of dependency targets that should be linked into this
+ # target. Add them to the dependencies list if they're not already
+ # present.
+
+ link_dependencies = dependency_nodes[target].LinkDependencies(targets)
+ for dependency in link_dependencies:
+ if dependency == target:
+ continue
+ if not 'dependencies' in target_dict:
+ target_dict['dependencies'] = []
+ if not dependency in target_dict['dependencies']:
+ target_dict['dependencies'].append(dependency)
+
+# Initialize this here to speed up MakePathRelative.
+exception_re = re.compile(r'''["']?[-/$<>]''')
+
+
+def MakePathRelative(to_file, fro_file, item):
+ # If item is a relative path, it's relative to the build file dict that it's
+ # coming from. Fix it up to make it relative to the build file dict that
+ # it's going into.
+ # Exception: any |item| that begins with these special characters is
+ # returned without modification.
+ # / Used when a path is already absolute (shortcut optimization;
+ # such paths would be returned as absolute anyway)
+ # $ Used for build environment variables
+ # - Used for some build environment flags (such as -lapr-1 in a
+ # "libraries" section)
+ # < Used for our own variable and command expansions (see ExpandVariables)
+ # > Used for our own variable and command expansions (see ExpandVariables)
+ #
+ # "/' Used when a value is quoted. If these are present, then we
+ # check the second character instead.
+ #
+ if to_file == fro_file or exception_re.match(item):
+ return item
+ else:
+ # TODO(dglazkov) The backslash/forward-slash replacement at the end is a
+ # temporary measure. This should really be addressed by keeping all paths
+ # in POSIX until actual project generation.
+ ret = os.path.normpath(os.path.join(
+ gyp.common.RelativePath(os.path.dirname(fro_file),
+ os.path.dirname(to_file)),
+ item)).replace('\\', '/')
+ if item[-1] == '/':
+ ret += '/'
+ return ret
+
+def MergeLists(to, fro, to_file, fro_file, is_paths=False, append=True):
+ prepend_index = 0
+
+ for item in fro:
+ singleton = False
+ if isinstance(item, str) or isinstance(item, int):
+ # The cheap and easy case.
+ if is_paths:
+ to_item = MakePathRelative(to_file, fro_file, item)
+ else:
+ to_item = item
+
+ if not isinstance(item, str) or not item.startswith('-'):
+ # Any string that doesn't begin with a "-" is a singleton - it can
+ # only appear once in a list, to be enforced by the list merge append
+ # or prepend.
+ singleton = True
+ elif isinstance(item, dict):
+ # Make a copy of the dictionary, continuing to look for paths to fix.
+ # The other intelligent aspects of merge processing won't apply because
+ # item is being merged into an empty dict.
+ to_item = {}
+ MergeDicts(to_item, item, to_file, fro_file)
+ elif isinstance(item, list):
+ # Recurse, making a copy of the list. If the list contains any
+ # descendant dicts, path fixing will occur. Note that here, custom
+ # values for is_paths and append are dropped; those are only to be
+ # applied to |to| and |fro|, not sublists of |fro|. append shouldn't
+ # matter anyway because the new |to_item| list is empty.
+ to_item = []
+ MergeLists(to_item, item, to_file, fro_file)
+ else:
+ raise TypeError, \
+ 'Attempt to merge list item of unsupported type ' + \
+ item.__class__.__name__
+
+ if append:
+ # If appending a singleton that's already in the list, don't append.
+ # This ensures that the earliest occurrence of the item will stay put.
+ if not singleton or not to_item in to:
+ to.append(to_item)
+ else:
+ # If prepending a singleton that's already in the list, remove the
+ # existing instance and proceed with the prepend. This ensures that the
+ # item appears at the earliest possible position in the list.
+ while singleton and to_item in to:
+ to.remove(to_item)
+
+ # Don't just insert everything at index 0. That would prepend the new
+ # items to the list in reverse order, which would be an unwelcome
+ # surprise.
+ to.insert(prepend_index, to_item)
+ prepend_index = prepend_index + 1
+
+
+def MergeDicts(to, fro, to_file, fro_file):
+ # I wanted to name the parameter "from" but it's a Python keyword...
+ for k, v in fro.iteritems():
+ # It would be nice to do "if not k in to: to[k] = v" but that wouldn't give
+ # copy semantics. Something else may want to merge from the |fro| dict
+ # later, and having the same dict ref pointed to twice in the tree isn't
+ # what anyone wants considering that the dicts may subsequently be
+ # modified.
+ if k in to:
+ bad_merge = False
+ if isinstance(v, str) or isinstance(v, int):
+ if not (isinstance(to[k], str) or isinstance(to[k], int)):
+ bad_merge = True
+ elif v.__class__ != to[k].__class__:
+ bad_merge = True
+
+ if bad_merge:
+ raise TypeError, \
+ 'Attempt to merge dict value of type ' + v.__class__.__name__ + \
+ ' into incompatible type ' + to[k].__class__.__name__ + \
+ ' for key ' + k
+ if isinstance(v, str) or isinstance(v, int):
+ # Overwrite the existing value, if any. Cheap and easy.
+ is_path = IsPathSection(k)
+ if is_path:
+ to[k] = MakePathRelative(to_file, fro_file, v)
+ else:
+ to[k] = v
+ elif isinstance(v, dict):
+ # Recurse, guaranteeing copies will be made of objects that require it.
+ if not k in to:
+ to[k] = {}
+ MergeDicts(to[k], v, to_file, fro_file)
+ elif isinstance(v, list):
+ # Lists in dicts can be merged with different policies, depending on
+ # how the key in the "from" dict (k, the from-key) is written.
+ #
+ # If the from-key has ...the to-list will have this action
+ # this character appended:... applied when receiving the from-list:
+ # = replace
+ # + prepend
+ # ? set, only if to-list does not yet exist
+ # (none) append
+ #
+ # This logic is list-specific, but since it relies on the associated
+ # dict key, it's checked in this dict-oriented function.
+ ext = k[-1]
+ append = True
+ if ext == '=':
+ list_base = k[:-1]
+ lists_incompatible = [list_base, list_base + '?']
+ to[list_base] = []
+ elif ext == '+':
+ list_base = k[:-1]
+ lists_incompatible = [list_base + '=', list_base + '?']
+ append = False
+ elif ext == '?':
+ list_base = k[:-1]
+ lists_incompatible = [list_base, list_base + '=', list_base + '+']
+ else:
+ list_base = k
+ lists_incompatible = [list_base + '=', list_base + '?']
+
+ # Some combinations of merge policies appearing together are meaningless.
+ # It's stupid to replace and append simultaneously, for example. Append
+ # and prepend are the only policies that can coexist.
+ for list_incompatible in lists_incompatible:
+ if list_incompatible in fro:
+ raise KeyError, 'Incompatible list policies ' + k + ' and ' + \
+ list_incompatible
+
+ if list_base in to:
+ if ext == '?':
+ # If the key ends in "?", the list will only be merged if it doesn't
+ # already exist.
+ continue
+ if not isinstance(to[list_base], list):
+ # This may not have been checked above if merging in a list with an
+ # extension character.
+ raise TypeError, \
+ 'Attempt to merge dict value of type ' + v.__class__.__name__ + \
+ ' into incompatible type ' + to[list_base].__class__.__name__ + \
+ ' for key ' + list_base + '(' + k + ')'
+ else:
+ to[list_base] = []
+
+ # Call MergeLists, which will make copies of objects that require it.
+ # MergeLists can recurse back into MergeDicts, although this will be
+ # to make copies of dicts (with paths fixed), there will be no
+ # subsequent dict "merging" once entering a list because lists are
+ # always replaced, appended to, or prepended to.
+ is_paths = IsPathSection(list_base)
+ MergeLists(to[list_base], v, to_file, fro_file, is_paths, append)
+ else:
+ raise TypeError, \
+ 'Attempt to merge dict value of unsupported type ' + \
+ v.__class__.__name__ + ' for key ' + k
+
+
+def MergeConfigWithInheritance(new_configuration_dict, build_file,
+ target_dict, configuration, visited):
+ # Skip if previously visted.
+ if configuration in visited:
+ return
+
+ # Look at this configuration.
+ configuration_dict = target_dict['configurations'][configuration]
+
+ # Merge in parents.
+ for parent in configuration_dict.get('inherit_from', []):
+ MergeConfigWithInheritance(new_configuration_dict, build_file,
+ target_dict, parent, visited + [configuration])
+
+ # Merge it into the new config.
+ MergeDicts(new_configuration_dict, configuration_dict,
+ build_file, build_file)
+
+ # Drop abstract.
+ if 'abstract' in new_configuration_dict:
+ del new_configuration_dict['abstract']
+
+
+def SetUpConfigurations(target, target_dict):
+ global non_configuration_keys
+ # key_suffixes is a list of key suffixes that might appear on key names.
+ # These suffixes are handled in conditional evaluations (for =, +, and ?)
+ # and rules/exclude processing (for ! and /). Keys with these suffixes
+ # should be treated the same as keys without.
+ key_suffixes = ['=', '+', '?', '!', '/']
+
+ build_file = gyp.common.BuildFile(target)
+
+ # Provide a single configuration by default if none exists.
+ # TODO(mark): Signal an error if default_configurations exists but
+ # configurations does not.
+ if not 'configurations' in target_dict:
+ target_dict['configurations'] = {'Default': {}}
+ if not 'default_configuration' in target_dict:
+ concrete = [i for i in target_dict['configurations'].keys()
+ if not target_dict['configurations'][i].get('abstract')]
+ target_dict['default_configuration'] = sorted(concrete)[0]
+
+ for configuration in target_dict['configurations'].keys():
+ old_configuration_dict = target_dict['configurations'][configuration]
+ # Skip abstract configurations (saves work only).
+ if old_configuration_dict.get('abstract'):
+ continue
+ # Configurations inherit (most) settings from the enclosing target scope.
+ # Get the inheritance relationship right by making a copy of the target
+ # dict.
+ new_configuration_dict = copy.deepcopy(target_dict)
+
+ # Take out the bits that don't belong in a "configurations" section.
+ # Since configuration setup is done before conditional, exclude, and rules
+ # processing, be careful with handling of the suffix characters used in
+ # those phases.
+ delete_keys = []
+ for key in new_configuration_dict:
+ key_ext = key[-1:]
+ if key_ext in key_suffixes:
+ key_base = key[:-1]
+ else:
+ key_base = key
+ if key_base in non_configuration_keys:
+ delete_keys.append(key)
+
+ for key in delete_keys:
+ del new_configuration_dict[key]
+
+ # Merge in configuration (with all its parents first).
+ MergeConfigWithInheritance(new_configuration_dict, build_file,
+ target_dict, configuration, [])
+
+ # Put the new result back into the target dict as a configuration.
+ target_dict['configurations'][configuration] = new_configuration_dict
+
+ # Now drop all the abstract ones.
+ for configuration in target_dict['configurations'].keys():
+ old_configuration_dict = target_dict['configurations'][configuration]
+ if old_configuration_dict.get('abstract'):
+ del target_dict['configurations'][configuration]
+
+ # Now that all of the target's configurations have been built, go through
+ # the target dict's keys and remove everything that's been moved into a
+ # "configurations" section.
+ delete_keys = []
+ for key in target_dict:
+ key_ext = key[-1:]
+ if key_ext in key_suffixes:
+ key_base = key[:-1]
+ else:
+ key_base = key
+ if not key_base in non_configuration_keys:
+ delete_keys.append(key)
+ for key in delete_keys:
+ del target_dict[key]
+
+ # Check the configurations to see if they contain invalid keys.
+ for configuration in target_dict['configurations'].keys():
+ configuration_dict = target_dict['configurations'][configuration]
+ for key in configuration_dict.keys():
+ if key in invalid_configuration_keys:
+ raise KeyError, ('%s not allowed in the %s configuration, found in '
+ 'target %s' % (key, configuration, target))
+
+
+
+def ProcessListFiltersInDict(name, the_dict):
+ """Process regular expression and exclusion-based filters on lists.
+
+ An exclusion list is in a dict key named with a trailing "!", like
+ "sources!". Every item in such a list is removed from the associated
+ main list, which in this example, would be "sources". Removed items are
+ placed into a "sources_excluded" list in the dict.
+
+ Regular expression (regex) filters are contained in dict keys named with a
+ trailing "/", such as "sources/" to operate on the "sources" list. Regex
+ filters in a dict take the form:
+ 'sources/': [ ['exclude', '_(linux|mac|win)\\.cc$'] ],
+ ['include', '_mac\\.cc$'] ],
+ The first filter says to exclude all files ending in _linux.cc, _mac.cc, and
+ _win.cc. The second filter then includes all files ending in _mac.cc that
+ are now or were once in the "sources" list. Items matching an "exclude"
+ filter are subject to the same processing as would occur if they were listed
+ by name in an exclusion list (ending in "!"). Items matching an "include"
+ filter are brought back into the main list if previously excluded by an
+ exclusion list or exclusion regex filter. Subsequent matching "exclude"
+ patterns can still cause items to be excluded after matching an "include".
+ """
+
+ # Look through the dictionary for any lists whose keys end in "!" or "/".
+ # These are lists that will be treated as exclude lists and regular
+ # expression-based exclude/include lists. Collect the lists that are
+ # needed first, looking for the lists that they operate on, and assemble
+ # then into |lists|. This is done in a separate loop up front, because
+ # the _included and _excluded keys need to be added to the_dict, and that
+ # can't be done while iterating through it.
+
+ lists = []
+ del_lists = []
+ for key, value in the_dict.iteritems():
+ operation = key[-1]
+ if operation != '!' and operation != '/':
+ continue
+
+ if not isinstance(value, list):
+ raise ValueError, name + ' key ' + key + ' must be list, not ' + \
+ value.__class__.__name__
+
+ list_key = key[:-1]
+ if list_key not in the_dict:
+ # This happens when there's a list like "sources!" but no corresponding
+ # "sources" list. Since there's nothing for it to operate on, queue up
+ # the "sources!" list for deletion now.
+ del_lists.append(key)
+ continue
+
+ if not isinstance(the_dict[list_key], list):
+ raise ValueError, name + ' key ' + list_key + \
+ ' must be list, not ' + \
+ value.__class__.__name__ + ' when applying ' + \
+ {'!': 'exclusion', '/': 'regex'}[operation]
+
+ if not list_key in lists:
+ lists.append(list_key)
+
+ # Delete the lists that are known to be unneeded at this point.
+ for del_list in del_lists:
+ del the_dict[del_list]
+
+ for list_key in lists:
+ the_list = the_dict[list_key]
+
+ # Initialize the list_actions list, which is parallel to the_list. Each
+ # item in list_actions identifies whether the corresponding item in
+ # the_list should be excluded, unconditionally preserved (included), or
+ # whether no exclusion or inclusion has been applied. Items for which
+ # no exclusion or inclusion has been applied (yet) have value -1, items
+ # excluded have value 0, and items included have value 1. Includes and
+ # excludes override previous actions. All items in list_actions are
+ # initialized to -1 because no excludes or includes have been processed
+ # yet.
+ list_actions = list((-1,) * len(the_list))
+
+ exclude_key = list_key + '!'
+ if exclude_key in the_dict:
+ for exclude_item in the_dict[exclude_key]:
+ for index in xrange(0, len(the_list)):
+ if exclude_item == the_list[index]:
+ # This item matches the exclude_item, so set its action to 0
+ # (exclude).
+ list_actions[index] = 0
+
+ # The "whatever!" list is no longer needed, dump it.
+ del the_dict[exclude_key]
+
+ regex_key = list_key + '/'
+ if regex_key in the_dict:
+ for regex_item in the_dict[regex_key]:
+ [action, pattern] = regex_item
+ pattern_re = re.compile(pattern)
+
+ for index in xrange(0, len(the_list)):
+ list_item = the_list[index]
+ if pattern_re.search(list_item):
+ # Regular expression match.
+
+ if action == 'exclude':
+ # This item matches an exclude regex, so set its value to 0
+ # (exclude).
+ list_actions[index] = 0
+ elif action == 'include':
+ # This item matches an include regex, so set its value to 1
+ # (include).
+ list_actions[index] = 1
+ else:
+ # This is an action that doesn't make any sense.
+ raise ValueError, 'Unrecognized action ' + action + ' in ' + \
+ name + ' key ' + key
+
+ # The "whatever/" list is no longer needed, dump it.
+ del the_dict[regex_key]
+
+ # Add excluded items to the excluded list.
+ #
+ # Note that exclude_key ("sources!") is different from excluded_key
+ # ("sources_excluded"). The exclude_key list is input and it was already
+ # processed and deleted; the excluded_key list is output and it's about
+ # to be created.
+ excluded_key = list_key + '_excluded'
+ if excluded_key in the_dict:
+ raise KeyError, \
+ name + ' key ' + excluded_key + ' must not be present prior ' + \
+ ' to applying exclusion/regex filters for ' + list_key
+
+ excluded_list = []
+
+ # Go backwards through the list_actions list so that as items are deleted,
+ # the indices of items that haven't been seen yet don't shift. That means
+ # that things need to be prepended to excluded_list to maintain them in the
+ # same order that they existed in the_list.
+ for index in xrange(len(list_actions) - 1, -1, -1):
+ if list_actions[index] == 0:
+ # Dump anything with action 0 (exclude). Keep anything with action 1
+ # (include) or -1 (no include or exclude seen for the item).
+ excluded_list.insert(0, the_list[index])
+ del the_list[index]
+
+ # If anything was excluded, put the excluded list into the_dict at
+ # excluded_key.
+ if len(excluded_list) > 0:
+ the_dict[excluded_key] = excluded_list
+
+ # Now recurse into subdicts and lists that may contain dicts.
+ for key, value in the_dict.iteritems():
+ if isinstance(value, dict):
+ ProcessListFiltersInDict(key, value)
+ elif isinstance(value, list):
+ ProcessListFiltersInList(key, value)
+
+
+def ProcessListFiltersInList(name, the_list):
+ for item in the_list:
+ if isinstance(item, dict):
+ ProcessListFiltersInDict(name, item)
+ elif isinstance(item, list):
+ ProcessListFiltersInList(name, item)
+
+
+def ValidateRulesInTarget(target, target_dict, extra_sources_for_rules):
+ """Ensures that the rules sections in target_dict are valid and consistent,
+ and determines which sources they apply to.
+
+ Arguments:
+ target: string, name of target.
+ target_dict: dict, target spec containing "rules" and "sources" lists.
+ extra_sources_for_rules: a list of keys to scan for rule matches in
+ addition to 'sources'.
+ """
+
+ # Dicts to map between values found in rules' 'rule_name' and 'extension'
+ # keys and the rule dicts themselves.
+ rule_names = {}
+ rule_extensions = {}
+
+ rules = target_dict.get('rules', [])
+ for rule in rules:
+ # Make sure that there's no conflict among rule names and extensions.
+ rule_name = rule['rule_name']
+ if rule_name in rule_names:
+ raise KeyError, 'rule %s exists in duplicate, target %s' % \
+ (rule_name, target)
+ rule_names[rule_name] = rule
+
+ rule_extension = rule['extension']
+ if rule_extension in rule_extensions:
+ raise KeyError, ('extension %s associated with multiple rules, ' +
+ 'target %s rules %s and %s') % \
+ (rule_extension, target,
+ rule_extensions[rule_extension]['rule_name'],
+ rule_name)
+ rule_extensions[rule_extension] = rule
+
+ # Make sure rule_sources isn't already there. It's going to be
+ # created below if needed.
+ if 'rule_sources' in rule:
+ raise KeyError, \
+ 'rule_sources must not exist in input, target %s rule %s' % \
+ (target, rule_name)
+ extension = rule['extension']
+
+ rule_sources = []
+ source_keys = ['sources']
+ source_keys.extend(extra_sources_for_rules)
+ for source_key in source_keys:
+ for source in target_dict.get(source_key, []):
+ (source_root, source_extension) = os.path.splitext(source)
+ if source_extension.startswith('.'):
+ source_extension = source_extension[1:]
+ if source_extension == extension:
+ rule_sources.append(source)
+
+ if len(rule_sources) > 0:
+ rule['rule_sources'] = rule_sources
+
+
+def ValidateActionsInTarget(target, target_dict, build_file):
+ '''Validates the inputs to the actions in a target.'''
+ target_name = target_dict.get('target_name')
+ actions = target_dict.get('actions', [])
+ for action in actions:
+ action_name = action.get('action_name')
+ if not action_name:
+ raise Exception("Anonymous action in target %s. "
+ "An action must have an 'action_name' field." %
+ target_name)
+ inputs = action.get('inputs', [])
+
+
+def ValidateRunAsInTarget(target, target_dict, build_file):
+ target_name = target_dict.get('target_name')
+ run_as = target_dict.get('run_as')
+ if not run_as:
+ return
+ if not isinstance(run_as, dict):
+ raise Exception("The 'run_as' in target %s from file %s should be a "
+ "dictionary." %
+ (target_name, build_file))
+ action = run_as.get('action')
+ if not action:
+ raise Exception("The 'run_as' in target %s from file %s must have an "
+ "'action' section." %
+ (target_name, build_file))
+ if not isinstance(action, list):
+ raise Exception("The 'action' for 'run_as' in target %s from file %s "
+ "must be a list." %
+ (target_name, build_file))
+ working_directory = run_as.get('working_directory')
+ if working_directory and not isinstance(working_directory, str):
+ raise Exception("The 'working_directory' for 'run_as' in target %s "
+ "in file %s should be a string." %
+ (target_name, build_file))
+ environment = run_as.get('environment')
+ if environment and not isinstance(environment, dict):
+ raise Exception("The 'environment' for 'run_as' in target %s "
+ "in file %s should be a dictionary." %
+ (target_name, build_file))
+
+
+def TurnIntIntoStrInDict(the_dict):
+ """Given dict the_dict, recursively converts all integers into strings.
+ """
+ # Use items instead of iteritems because there's no need to try to look at
+ # reinserted keys and their associated values.
+ for k, v in the_dict.items():
+ if isinstance(v, int):
+ v = str(v)
+ the_dict[k] = v
+ elif isinstance(v, dict):
+ TurnIntIntoStrInDict(v)
+ elif isinstance(v, list):
+ TurnIntIntoStrInList(v)
+
+ if isinstance(k, int):
+ the_dict[str(k)] = v
+ del the_dict[k]
+
+
+def TurnIntIntoStrInList(the_list):
+ """Given list the_list, recursively converts all integers into strings.
+ """
+ for index in xrange(0, len(the_list)):
+ item = the_list[index]
+ if isinstance(item, int):
+ the_list[index] = str(item)
+ elif isinstance(item, dict):
+ TurnIntIntoStrInDict(item)
+ elif isinstance(item, list):
+ TurnIntIntoStrInList(item)
+
+
+def VerifyNoCollidingTargets(targets):
+ """Verify that no two targets in the same directory share the same name.
+
+ Arguments:
+ targets: A list of targets in the form 'path/to/file.gyp:target_name'.
+ """
+ # Keep a dict going from 'subdirectory:target_name' to 'foo.gyp'.
+ used = {}
+ for target in targets:
+ # Separate out 'path/to/file.gyp, 'target_name' from
+ # 'path/to/file.gyp:target_name'.
+ path, name = target.split(':')
+ # Separate out 'path/to', 'file.gyp' from 'path/to/file.gyp'.
+ subdir, gyp = os.path.split(path)
+ # Use '.' for the current directory '', so that the error messages make
+ # more sense.
+ if not subdir:
+ subdir = '.'
+ # Prepare a key like 'path/to:target_name'.
+ key = subdir + ':' + name
+ if key in used:
+ # Complain if this target is already used.
+ raise Exception('Duplicate target name "%s" in directory "%s" used both '
+ 'in "%s" and "%s".' % (name, subdir, gyp, used[key]))
+ used[key] = gyp
+
+
+def Load(build_files, variables, includes, depth, generator_input_info, check,
+ circular_check):
+ # Set up path_sections and non_configuration_keys with the default data plus
+ # the generator-specifc data.
+ global path_sections
+ path_sections = base_path_sections[:]
+ path_sections.extend(generator_input_info['path_sections'])
+
+ global non_configuration_keys
+ non_configuration_keys = base_non_configuration_keys[:]
+ non_configuration_keys.extend(generator_input_info['non_configuration_keys'])
+
+ # TODO(mark) handle variants if the generator doesn't want them directly.
+ generator_handles_variants = \
+ generator_input_info['generator_handles_variants']
+
+ global absolute_build_file_paths
+ absolute_build_file_paths = \
+ generator_input_info['generator_wants_absolute_build_file_paths']
+
+ global multiple_toolsets
+ multiple_toolsets = generator_input_info[
+ 'generator_supports_multiple_toolsets']
+
+ # A generator can have other lists (in addition to sources) be processed
+ # for rules.
+ extra_sources_for_rules = generator_input_info['extra_sources_for_rules']
+
+ # Load build files. This loads every target-containing build file into
+ # the |data| dictionary such that the keys to |data| are build file names,
+ # and the values are the entire build file contents after "early" or "pre"
+ # processing has been done and includes have been resolved.
+ # NOTE: data contains both "target" files (.gyp) and "includes" (.gypi), as
+ # well as meta-data (e.g. 'included_files' key). 'target_build_files' keeps
+ # track of the keys corresponding to "target" files.
+ data = {'target_build_files': set()}
+ aux_data = {}
+ for build_file in build_files:
+ # Normalize paths everywhere. This is important because paths will be
+ # used as keys to the data dict and for references between input files.
+ build_file = os.path.normpath(build_file)
+ try:
+ LoadTargetBuildFile(build_file, data, aux_data, variables, includes,
+ depth, check)
+ except Exception, e:
+ gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file)
+ raise
+
+ # Build a dict to access each target's subdict by qualified name.
+ targets = BuildTargetsDict(data)
+
+ # Fully qualify all dependency links.
+ QualifyDependencies(targets)
+
+ # Expand dependencies specified as build_file:*.
+ ExpandWildcardDependencies(targets, data)
+
+ if circular_check:
+ # Make sure that any targets in a.gyp don't contain dependencies in other
+ # .gyp files that further depend on a.gyp.
+ VerifyNoGYPFileCircularDependencies(targets)
+
+ [dependency_nodes, flat_list] = BuildDependencyList(targets)
+
+ # Check that no two targets in the same directory have the same name.
+ VerifyNoCollidingTargets(flat_list)
+
+
+ # Handle dependent settings of various types.
+ for settings_type in ['all_dependent_settings',
+ 'direct_dependent_settings',
+ 'link_settings']:
+ DoDependentSettings(settings_type, flat_list, targets, dependency_nodes)
+
+ # Take out the dependent settings now that they've been published to all
+ # of the targets that require them.
+ for target in flat_list:
+ if settings_type in targets[target]:
+ del targets[target][settings_type]
+
+ # Make sure static libraries don't declare dependencies on other static
+ # libraries, but that linkables depend on all unlinked static libraries
+ # that they need so that their link steps will be correct.
+ AdjustStaticLibraryDependencies(flat_list, targets, dependency_nodes)
+
+ # Apply "post"/"late"/"target" variable expansions and condition evaluations.
+ for target in flat_list:
+ target_dict = targets[target]
+ build_file = gyp.common.BuildFile(target)
+ ProcessVariablesAndConditionsInDict(target_dict, True, variables,
+ build_file)
+
+ # Move everything that can go into a "configurations" section into one.
+ for target in flat_list:
+ target_dict = targets[target]
+ SetUpConfigurations(target, target_dict)
+
+ # Apply exclude (!) and regex (/) list filters.
+ for target in flat_list:
+ target_dict = targets[target]
+ ProcessListFiltersInDict(target, target_dict)
+
+ # Make sure that the rules make sense, and build up rule_sources lists as
+ # needed. Not all generators will need to use the rule_sources lists, but
+ # some may, and it seems best to build the list in a common spot.
+ # Also validate actions and run_as elements in targets.
+ for target in flat_list:
+ target_dict = targets[target]
+ build_file = gyp.common.BuildFile(target)
+ ValidateRulesInTarget(target, target_dict, extra_sources_for_rules)
+ ValidateRunAsInTarget(target, target_dict, build_file)
+ ValidateActionsInTarget(target, target_dict, build_file)
+
+ # Generators might not expect ints. Turn them into strs.
+ TurnIntIntoStrInDict(data)
+
+ # TODO(mark): Return |data| for now because the generator needs a list of
+ # build files that came in. In the future, maybe it should just accept
+ # a list, and not the whole data dict.
+ return [flat_list, targets, data]
diff --git a/Source/ThirdParty/gyp/pylib/gyp/system_test.py b/Source/ThirdParty/gyp/pylib/gyp/system_test.py
new file mode 100644
index 000000000..7aa2d93dc
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/system_test.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import tempfile
+import shutil
+import subprocess
+
+def TestCommands(commands, files={}, env={}):
+ """Run commands in a temporary directory, returning true if they all succeed.
+ Return false on failures or if any commands produce output.
+
+ Arguments:
+ commands: an array of shell-interpretable commands, e.g. ['ls -l', 'pwd']
+ each will be expanded with Python %-expansion using env first.
+ files: a dictionary mapping filename to contents;
+ files will be created in the temporary directory before running
+ the command.
+ env: a dictionary of strings to expand commands with.
+ """
+ tempdir = tempfile.mkdtemp()
+ try:
+ for name, contents in files.items():
+ f = open(os.path.join(tempdir, name), 'wb')
+ f.write(contents)
+ f.close()
+ for command in commands:
+ proc = subprocess.Popen(command % env, shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ cwd=tempdir)
+ output = proc.communicate()[0]
+ if proc.returncode != 0 or output:
+ return False
+ return True
+ finally:
+ shutil.rmtree(tempdir)
+ return False
+
+
+def TestArSupportsT(ar_command='ar', cc_command='cc'):
+ """Test whether 'ar' supports the 'T' flag."""
+ return TestCommands(['%(cc)s -c test.c',
+ '%(ar)s crsT test.a test.o',
+ '%(cc)s test.a'],
+ files={'test.c': 'int main(){}'},
+ env={'ar': ar_command, 'cc': cc_command})
+
+
+def TestLinkerSupportsThreads(cc_command='cc'):
+ """Test whether the linker supports the --threads flag."""
+ return TestCommands(['%(cc)s -Wl,--threads test.c'],
+ files={'test.c': 'int main(){}'},
+ env={'cc': cc_command})
+
+
+if __name__ == '__main__':
+ # Run the various test functions and print the results.
+ def RunTest(description, function, **kwargs):
+ print "Testing " + description + ':',
+ if function(**kwargs):
+ print 'ok'
+ else:
+ print 'fail'
+ RunTest("ar 'T' flag", TestArSupportsT)
+ RunTest("ar 'T' flag with ccache", TestArSupportsT, cc_command='ccache cc')
+ RunTest("ld --threads", TestLinkerSupportsThreads)
diff --git a/Source/ThirdParty/gyp/pylib/gyp/xcodeproj_file.py b/Source/ThirdParty/gyp/pylib/gyp/xcodeproj_file.py
new file mode 100644
index 000000000..fcf9abfe4
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/xcodeproj_file.py
@@ -0,0 +1,2840 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Xcode project file generator.
+
+This module is both an Xcode project file generator and a documentation of the
+Xcode project file format. Knowledge of the project file format was gained
+based on extensive experience with Xcode, and by making changes to projects in
+Xcode.app and observing the resultant changes in the associated project files.
+
+XCODE PROJECT FILES
+
+The generator targets the file format as written by Xcode 3.1 (specifically,
+3.1.2), but past experience has taught that the format has not changed
+significantly in the past several years, and future versions of Xcode are able
+to read older project files.
+
+Xcode project files are "bundled": the project "file" from an end-user's
+perspective is actually a directory with an ".xcodeproj" extension. The
+project file from this module's perspective is actually a file inside this
+directory, always named "project.pbxproj". This file contains a complete
+description of the project and is all that is needed to use the xcodeproj.
+Other files contained in the xcodeproj directory are simply used to store
+per-user settings, such as the state of various UI elements in the Xcode
+application.
+
+The project.pbxproj file is a property list, stored in a format almost
+identical to the NeXTstep property list format. The file is able to carry
+Unicode data, and is encoded in UTF-8. The root element in the property list
+is a dictionary that contains several properties of minimal interest, and two
+properties of immense interest. The most important property is a dictionary
+named "objects". The entire structure of the project is represented by the
+children of this property. The objects dictionary is keyed by unique 96-bit
+values represented by 24 uppercase hexadecimal characters. Each value in the
+objects dictionary is itself a dictionary, describing an individual object.
+
+Each object in the dictionary is a member of a class, which is identified by
+the "isa" property of each object. A variety of classes are represented in a
+project file. Objects can refer to other objects by ID, using the 24-character
+hexadecimal object key. A project's objects form a tree, with a root object
+of class PBXProject at the root. As an example, the PBXProject object serves
+as parent to an XCConfigurationList object defining the build configurations
+used in the project, a PBXGroup object serving as a container for all files
+referenced in the project, and a list of target objects, each of which defines
+a target in the project. There are several different types of target object,
+such as PBXNativeTarget and PBXAggregateTarget. In this module, this
+relationship is expressed by having each target type derive from an abstract
+base named XCTarget.
+
+The project.pbxproj file's root dictionary also contains a property, sibling to
+the "objects" dictionary, named "rootObject". The value of rootObject is a
+24-character object key referring to the root PBXProject object in the
+objects dictionary.
+
+In Xcode, every file used as input to a target or produced as a final product
+of a target must appear somewhere in the hierarchy rooted at the PBXGroup
+object referenced by the PBXProject's mainGroup property. A PBXGroup is
+generally represented as a folder in the Xcode application. PBXGroups can
+contain other PBXGroups as well as PBXFileReferences, which are pointers to
+actual files.
+
+Each XCTarget contains a list of build phases, represented in this module by
+the abstract base XCBuildPhase. Examples of concrete XCBuildPhase derivations
+are PBXSourcesBuildPhase and PBXFrameworksBuildPhase, which correspond to the
+"Compile Sources" and "Link Binary With Libraries" phases displayed in the
+Xcode application. Files used as input to these phases (for example, source
+files in the former case and libraries and frameworks in the latter) are
+represented by PBXBuildFile objects, referenced by elements of "files" lists
+in XCTarget objects. Each PBXBuildFile object refers to a PBXBuildFile
+object as a "weak" reference: it does not "own" the PBXBuildFile, which is
+owned by the root object's mainGroup or a descendant group. In most cases, the
+layer of indirection between an XCBuildPhase and a PBXFileReference via a
+PBXBuildFile appears extraneous, but there's actually one reason for this:
+file-specific compiler flags are added to the PBXBuildFile object so as to
+allow a single file to be a member of multiple targets while having distinct
+compiler flags for each. These flags can be modified in the Xcode applciation
+in the "Build" tab of a File Info window.
+
+When a project is open in the Xcode application, Xcode will rewrite it. As
+such, this module is careful to adhere to the formatting used by Xcode, to
+avoid insignificant changes appearing in the file when it is used in the
+Xcode application. This will keep version control repositories happy, and
+makes it possible to compare a project file used in Xcode to one generated by
+this module to determine if any significant changes were made in the
+application.
+
+Xcode has its own way of assigning 24-character identifiers to each object,
+which is not duplicated here. Because the identifier only is only generated
+once, when an object is created, and is then left unchanged, there is no need
+to attempt to duplicate Xcode's behavior in this area. The generator is free
+to select any identifier, even at random, to refer to the objects it creates,
+and Xcode will retain those identifiers and use them when subsequently
+rewriting the project file. However, the generator would choose new random
+identifiers each time the project files are generated, leading to difficulties
+comparing "used" project files to "pristine" ones produced by this module,
+and causing the appearance of changes as every object identifier is changed
+when updated projects are checked in to a version control repository. To
+mitigate this problem, this module chooses identifiers in a more deterministic
+way, by hashing a description of each object as well as its parent and ancestor
+objects. This strategy should result in minimal "shift" in IDs as successive
+generations of project files are produced.
+
+THIS MODULE
+
+This module introduces several classes, all derived from the XCObject class.
+Nearly all of the "brains" are built into the XCObject class, which understands
+how to create and modify objects, maintain the proper tree structure, compute
+identifiers, and print objects. For the most part, classes derived from
+XCObject need only provide a _schema class object, a dictionary that
+expresses what properties objects of the class may contain.
+
+Given this structure, it's possible to build a minimal project file by creating
+objects of the appropriate types and making the proper connections:
+
+ config_list = XCConfigurationList()
+ group = PBXGroup()
+ project = PBXProject({'buildConfigurationList': config_list,
+ 'mainGroup': group})
+
+With the project object set up, it can be added to an XCProjectFile object.
+XCProjectFile is a pseudo-class in the sense that it is a concrete XCObject
+subclass that does not actually correspond to a class type found in a project
+file. Rather, it is used to represent the project file's root dictionary.
+Printing an XCProjectFile will print the entire project file, including the
+full "objects" dictionary.
+
+ project_file = XCProjectFile({'rootObject': project})
+ project_file.ComputeIDs()
+ project_file.Print()
+
+Xcode project files are always encoded in UTF-8. This module will accept
+strings of either the str class or the unicode class. Strings of class str
+are assumed to already be encoded in UTF-8. Obviously, if you're just using
+ASCII, you won't encounter difficulties because ASCII is a UTF-8 subset.
+Strings of class unicode are handled properly and encoded in UTF-8 when
+a project file is output.
+"""
+
+import gyp.common
+import posixpath
+import re
+import struct
+import sys
+
+# hashlib is supplied as of Python 2.5 as the replacement interface for sha
+# and other secure hashes. In 2.6, sha is deprecated. Import hashlib if
+# available, avoiding a deprecation warning under 2.6. Import sha otherwise,
+# preserving 2.4 compatibility.
+try:
+ import hashlib
+ _new_sha1 = hashlib.sha1
+except ImportError:
+ import sha
+ _new_sha1 = sha.new
+
+
+# See XCObject._EncodeString. This pattern is used to determine when a string
+# can be printed unquoted. Strings that match this pattern may be printed
+# unquoted. Strings that do not match must be quoted and may be further
+# transformed to be properly encoded. Note that this expression matches the
+# characters listed with "+", for 1 or more occurrences: if a string is empty,
+# it must not match this pattern, because it needs to be encoded as "".
+_unquoted = re.compile('^[A-Za-z0-9$./_]+$')
+
+# Strings that match this pattern are quoted regardless of what _unquoted says.
+# Oddly, Xcode will quote any string with a run of three or more underscores.
+_quoted = re.compile('___')
+
+# This pattern should match any character that needs to be escaped by
+# XCObject._EncodeString. See that function.
+_escaped = re.compile('[\\\\"]|[^ -~]')
+
+
+# Used by SourceTreeAndPathFromPath
+_path_leading_variable = re.compile('^\$\((.*?)\)(/(.*))?$')
+
+def SourceTreeAndPathFromPath(input_path):
+ """Given input_path, returns a tuple with sourceTree and path values.
+
+ Examples:
+ input_path (source_tree, output_path)
+ '$(VAR)/path' ('VAR', 'path')
+ '$(VAR)' ('VAR', None)
+ 'path' (None, 'path')
+ """
+
+ source_group_match = _path_leading_variable.match(input_path)
+ if source_group_match:
+ source_tree = source_group_match.group(1)
+ output_path = source_group_match.group(3) # This may be None.
+ else:
+ source_tree = None
+ output_path = input_path
+
+ return (source_tree, output_path)
+
+def ConvertVariablesToShellSyntax(input_string):
+ return re.sub('\$\((.*?)\)', '${\\1}', input_string)
+
+class XCObject(object):
+ """The abstract base of all class types used in Xcode project files.
+
+ Class variables:
+ _schema: A dictionary defining the properties of this class. The keys to
+ _schema are string property keys as used in project files. Values
+ are a list of four or five elements:
+ [ is_list, property_type, is_strong, is_required, default ]
+ is_list: True if the property described is a list, as opposed
+ to a single element.
+ property_type: The type to use as the value of the property,
+ or if is_list is True, the type to use for each
+ element of the value's list. property_type must
+ be an XCObject subclass, or one of the built-in
+ types str, int, or dict.
+ is_strong: If property_type is an XCObject subclass, is_strong
+ is True to assert that this class "owns," or serves
+ as parent, to the property value (or, if is_list is
+ True, values). is_strong must be False if
+ property_type is not an XCObject subclass.
+ is_required: True if the property is required for the class.
+ Note that is_required being True does not preclude
+ an empty string ("", in the case of property_type
+ str) or list ([], in the case of is_list True) from
+ being set for the property.
+ default: Optional. If is_requried is True, default may be set
+ to provide a default value for objects that do not supply
+ their own value. If is_required is True and default
+ is not provided, users of the class must supply their own
+ value for the property.
+ Note that although the values of the array are expressed in
+ boolean terms, subclasses provide values as integers to conserve
+ horizontal space.
+ _should_print_single_line: False in XCObject. Subclasses whose objects
+ should be written to the project file in the
+ alternate single-line format, such as
+ PBXFileReference and PBXBuildFile, should
+ set this to True.
+ _encode_transforms: Used by _EncodeString to encode unprintable characters.
+ The index into this list is the ordinal of the
+ character to transform; each value is a string
+ used to represent the character in the output. XCObject
+ provides an _encode_transforms list suitable for most
+ XCObject subclasses.
+ _alternate_encode_transforms: Provided for subclasses that wish to use
+ the alternate encoding rules. Xcode seems
+ to use these rules when printing objects in
+ single-line format. Subclasses that desire
+ this behavior should set _encode_transforms
+ to _alternate_encode_transforms.
+ _hashables: A list of XCObject subclasses that can be hashed by ComputeIDs
+ to construct this object's ID. Most classes that need custom
+ hashing behavior should do it by overriding Hashables,
+ but in some cases an object's parent may wish to push a
+ hashable value into its child, and it can do so by appending
+ to _hashables.
+ Attribues:
+ id: The object's identifier, a 24-character uppercase hexadecimal string.
+ Usually, objects being created should not set id until the entire
+ project file structure is built. At that point, UpdateIDs() should
+ be called on the root object to assign deterministic values for id to
+ each object in the tree.
+ parent: The object's parent. This is set by a parent XCObject when a child
+ object is added to it.
+ _properties: The object's property dictionary. An object's properties are
+ described by its class' _schema variable.
+ """
+
+ _schema = {}
+ _should_print_single_line = False
+
+ # See _EncodeString.
+ _encode_transforms = []
+ i = 0
+ while i < ord(' '):
+ _encode_transforms.append('\\U%04x' % i)
+ i = i + 1
+ _encode_transforms[7] = '\\a'
+ _encode_transforms[8] = '\\b'
+ _encode_transforms[9] = '\\t'
+ _encode_transforms[10] = '\\n'
+ _encode_transforms[11] = '\\v'
+ _encode_transforms[12] = '\\f'
+ _encode_transforms[13] = '\\n'
+
+ _alternate_encode_transforms = list(_encode_transforms)
+ _alternate_encode_transforms[9] = chr(9)
+ _alternate_encode_transforms[10] = chr(10)
+ _alternate_encode_transforms[11] = chr(11)
+
+ def __init__(self, properties=None, id=None, parent=None):
+ self.id = id
+ self.parent = parent
+ self._properties = {}
+ self._hashables = []
+ self._SetDefaultsFromSchema()
+ self.UpdateProperties(properties)
+
+ def __repr__(self):
+ try:
+ name = self.Name()
+ except NotImplementedError:
+ return '<%s at 0x%x>' % (self.__class__.__name__, id(self))
+ return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+
+ def Copy(self):
+ """Make a copy of this object.
+
+ The new object will have its own copy of lists and dicts. Any XCObject
+ objects owned by this object (marked "strong") will be copied in the
+ new object, even those found in lists. If this object has any weak
+ references to other XCObjects, the same references are added to the new
+ object without making a copy.
+ """
+
+ that = self.__class__(id=self.id, parent=self.parent)
+ for key, value in self._properties.iteritems():
+ is_strong = self._schema[key][2]
+
+ if isinstance(value, XCObject):
+ if is_strong:
+ new_value = value.Copy()
+ new_value.parent = that
+ that._properties[key] = new_value
+ else:
+ that._properties[key] = value
+ elif isinstance(value, str) or isinstance(value, unicode) or \
+ isinstance(value, int):
+ that._properties[key] = value
+ elif isinstance(value, list):
+ if is_strong:
+ # If is_strong is True, each element is an XCObject, so it's safe to
+ # call Copy.
+ that._properties[key] = []
+ for item in value:
+ new_item = item.Copy()
+ new_item.parent = that
+ that._properties[key].append(new_item)
+ else:
+ that._properties[key] = value[:]
+ elif isinstance(value, dict):
+ # dicts are never strong.
+ if is_strong:
+ raise TypeError, 'Strong dict for key ' + key + ' in ' + \
+ self.__class__.__name__
+ else:
+ that._properties[key] = value.copy()
+ else:
+ raise TypeError, 'Unexpected type ' + value.__class__.__name__ + \
+ ' for key ' + key + ' in ' + self.__class__.__name__
+
+ return that
+
+ def Name(self):
+ """Return the name corresponding to an object.
+
+ Not all objects necessarily need to be nameable, and not all that do have
+ a "name" property. Override as needed.
+ """
+
+ # If the schema indicates that "name" is required, try to access the
+ # property even if it doesn't exist. This will result in a KeyError
+ # being raised for the property that should be present, which seems more
+ # appropriate than NotImplementedError in this case.
+ if 'name' in self._properties or \
+ ('name' in self._schema and self._schema['name'][3]):
+ return self._properties['name']
+
+ raise NotImplementedError, \
+ self.__class__.__name__ + ' must implement Name'
+
+ def Comment(self):
+ """Return a comment string for the object.
+
+ Most objects just use their name as the comment, but PBXProject uses
+ different values.
+
+ The returned comment is not escaped and does not have any comment marker
+ strings applied to it.
+ """
+
+ return self.Name()
+
+ def Hashables(self):
+ hashables = [self.__class__.__name__]
+
+ name = self.Name()
+ if name != None:
+ hashables.append(name)
+
+ hashables.extend(self._hashables)
+
+ return hashables
+
+ def ComputeIDs(self, recursive=True, overwrite=True, hash=None):
+ """Set "id" properties deterministically.
+
+ An object's "id" property is set based on a hash of its class type and
+ name, as well as the class type and name of all ancestor objects. As
+ such, it is only advisable to call ComputeIDs once an entire project file
+ tree is built.
+
+ If recursive is True, recurse into all descendant objects and update their
+ hashes.
+
+ If overwrite is True, any existing value set in the "id" property will be
+ replaced.
+ """
+
+ def _HashUpdate(hash, data):
+ """Update hash with data's length and contents.
+
+ If the hash were updated only with the value of data, it would be
+ possible for clowns to induce collisions by manipulating the names of
+ their objects. By adding the length, it's exceedingly less likely that
+ ID collisions will be encountered, intentionally or not.
+ """
+
+ hash.update(struct.pack('>i', len(data)))
+ hash.update(data)
+
+ if hash == None:
+ hash = _new_sha1()
+
+ hashables = self.Hashables()
+ assert len(hashables) > 0
+ for hashable in hashables:
+ _HashUpdate(hash, hashable)
+
+ if recursive:
+ for child in self.Children():
+ child.ComputeIDs(recursive, overwrite, hash.copy())
+
+ if overwrite or self.id == None:
+ # Xcode IDs are only 96 bits (24 hex characters), but a SHA-1 digest is
+ # is 160 bits. Instead of throwing out 64 bits of the digest, xor them
+ # into the portion that gets used.
+ assert hash.digest_size % 4 == 0
+ digest_int_count = hash.digest_size / 4
+ digest_ints = struct.unpack('>' + 'I' * digest_int_count, hash.digest())
+ id_ints = [0, 0, 0]
+ for index in xrange(0, digest_int_count):
+ id_ints[index % 3] ^= digest_ints[index]
+ self.id = '%08X%08X%08X' % tuple(id_ints)
+
+ def EnsureNoIDCollisions(self):
+ """Verifies that no two objects have the same ID. Checks all descendants.
+ """
+
+ ids = {}
+ descendants = self.Descendants()
+ for descendant in descendants:
+ if descendant.id in ids:
+ other = ids[descendant.id]
+ raise KeyError, \
+ 'Duplicate ID %s, objects "%s" and "%s" in "%s"' % \
+ (descendant.id, str(descendant._properties),
+ str(other._properties), self._properties['rootObject'].Name())
+ ids[descendant.id] = descendant
+
+ def Children(self):
+ """Returns a list of all of this object's owned (strong) children."""
+
+ children = []
+ for property, attributes in self._schema.iteritems():
+ (is_list, property_type, is_strong) = attributes[0:3]
+ if is_strong and property in self._properties:
+ if not is_list:
+ children.append(self._properties[property])
+ else:
+ children.extend(self._properties[property])
+ return children
+
+ def Descendants(self):
+ """Returns a list of all of this object's descendants, including this
+ object.
+ """
+
+ children = self.Children()
+ descendants = [self]
+ for child in children:
+ descendants.extend(child.Descendants())
+ return descendants
+
+ def PBXProjectAncestor(self):
+ # The base case for recursion is defined at PBXProject.PBXProjectAncestor.
+ if self.parent:
+ return self.parent.PBXProjectAncestor()
+ return None
+
+ def _EncodeComment(self, comment):
+ """Encodes a comment to be placed in the project file output, mimicing
+ Xcode behavior.
+ """
+
+ # This mimics Xcode behavior by wrapping the comment in "/*" and "*/". If
+ # the string already contains a "*/", it is turned into "(*)/". This keeps
+ # the file writer from outputting something that would be treated as the
+ # end of a comment in the middle of something intended to be entirely a
+ # comment.
+
+ return '/* ' + comment.replace('*/', '(*)/') + ' */'
+
+ def _EncodeTransform(self, match):
+ # This function works closely with _EncodeString. It will only be called
+ # by re.sub with match.group(0) containing a character matched by the
+ # the _escaped expression.
+ char = match.group(0)
+
+ # Backslashes (\) and quotation marks (") are always replaced with a
+ # backslash-escaped version of the same. Everything else gets its
+ # replacement from the class' _encode_transforms array.
+ if char == '\\':
+ return '\\\\'
+ if char == '"':
+ return '\\"'
+ return self._encode_transforms[ord(char)]
+
+ def _EncodeString(self, value):
+ """Encodes a string to be placed in the project file output, mimicing
+ Xcode behavior.
+ """
+
+ # Use quotation marks when any character outside of the range A-Z, a-z, 0-9,
+ # $ (dollar sign), . (period), and _ (underscore) is present. Also use
+ # quotation marks to represent empty strings.
+ #
+ # Escape " (double-quote) and \ (backslash) by preceding them with a
+ # backslash.
+ #
+ # Some characters below the printable ASCII range are encoded specially:
+ # 7 ^G BEL is encoded as "\a"
+ # 8 ^H BS is encoded as "\b"
+ # 11 ^K VT is encoded as "\v"
+ # 12 ^L NP is encoded as "\f"
+ # 127 ^? DEL is passed through as-is without escaping
+ # - In PBXFileReference and PBXBuildFile objects:
+ # 9 ^I HT is passed through as-is without escaping
+ # 10 ^J NL is passed through as-is without escaping
+ # 13 ^M CR is passed through as-is without escaping
+ # - In other objects:
+ # 9 ^I HT is encoded as "\t"
+ # 10 ^J NL is encoded as "\n"
+ # 13 ^M CR is encoded as "\n" rendering it indistinguishable from
+ # 10 ^J NL
+ # All other nonprintable characters within the ASCII range (0 through 127
+ # inclusive) are encoded as "\U001f" referring to the Unicode code point in
+ # hexadecimal. For example, character 14 (^N SO) is encoded as "\U000e".
+ # Characters above the ASCII range are passed through to the output encoded
+ # as UTF-8 without any escaping. These mappings are contained in the
+ # class' _encode_transforms list.
+
+ if _unquoted.search(value) and not _quoted.search(value):
+ return value
+
+ return '"' + _escaped.sub(self._EncodeTransform, value) + '"'
+
+ def _XCPrint(self, file, tabs, line):
+ file.write('\t' * tabs + line)
+
+ def _XCPrintableValue(self, tabs, value, flatten_list=False):
+ """Returns a representation of value that may be printed in a project file,
+ mimicing Xcode's behavior.
+
+ _XCPrintableValue can handle str and int values, XCObjects (which are
+ made printable by returning their id property), and list and dict objects
+ composed of any of the above types. When printing a list or dict, and
+ _should_print_single_line is False, the tabs parameter is used to determine
+ how much to indent the lines corresponding to the items in the list or
+ dict.
+
+ If flatten_list is True, single-element lists will be transformed into
+ strings.
+ """
+
+ printable = ''
+ comment = None
+
+ if self._should_print_single_line:
+ sep = ' '
+ element_tabs = ''
+ end_tabs = ''
+ else:
+ sep = '\n'
+ element_tabs = '\t' * (tabs + 1)
+ end_tabs = '\t' * tabs
+
+ if isinstance(value, XCObject):
+ printable += value.id
+ comment = value.Comment()
+ elif isinstance(value, str):
+ printable += self._EncodeString(value)
+ elif isinstance(value, unicode):
+ printable += self._EncodeString(value.encode('utf-8'))
+ elif isinstance(value, int):
+ printable += str(value)
+ elif isinstance(value, list):
+ if flatten_list and len(value) <= 1:
+ if len(value) == 0:
+ printable += self._EncodeString('')
+ else:
+ printable += self._EncodeString(value[0])
+ else:
+ printable = '(' + sep
+ for item in value:
+ printable += element_tabs + \
+ self._XCPrintableValue(tabs + 1, item, flatten_list) + \
+ ',' + sep
+ printable += end_tabs + ')'
+ elif isinstance(value, dict):
+ printable = '{' + sep
+ for item_key, item_value in sorted(value.iteritems()):
+ printable += element_tabs + \
+ self._XCPrintableValue(tabs + 1, item_key, flatten_list) + ' = ' + \
+ self._XCPrintableValue(tabs + 1, item_value, flatten_list) + ';' + \
+ sep
+ printable += end_tabs + '}'
+ else:
+ raise TypeError, "Can't make " + value.__class__.__name__ + ' printable'
+
+ if comment != None:
+ printable += ' ' + self._EncodeComment(comment)
+
+ return printable
+
+ def _XCKVPrint(self, file, tabs, key, value):
+ """Prints a key and value, members of an XCObject's _properties dictionary,
+ to file.
+
+ tabs is an int identifying the indentation level. If the class'
+ _should_print_single_line variable is True, tabs is ignored and the
+ key-value pair will be followed by a space insead of a newline.
+ """
+
+ if self._should_print_single_line:
+ printable = ''
+ after_kv = ' '
+ else:
+ printable = '\t' * tabs
+ after_kv = '\n'
+
+ # Xcode usually prints remoteGlobalIDString values in PBXContainerItemProxy
+ # objects without comments. Sometimes it prints them with comments, but
+ # the majority of the time, it doesn't. To avoid unnecessary changes to
+ # the project file after Xcode opens it, don't write comments for
+ # remoteGlobalIDString. This is a sucky hack and it would certainly be
+ # cleaner to extend the schema to indicate whether or not a comment should
+ # be printed, but since this is the only case where the problem occurs and
+ # Xcode itself can't seem to make up its mind, the hack will suffice.
+ #
+ # Also see PBXContainerItemProxy._schema['remoteGlobalIDString'].
+ if key == 'remoteGlobalIDString' and isinstance(self,
+ PBXContainerItemProxy):
+ value_to_print = value.id
+ else:
+ value_to_print = value
+
+ # PBXBuildFile's settings property is represented in the output as a dict,
+ # but a hack here has it represented as a string. Arrange to strip off the
+ # quotes so that it shows up in the output as expected.
+ if key == 'settings' and isinstance(self, PBXBuildFile):
+ strip_value_quotes = True
+ else:
+ strip_value_quotes = False
+
+ # In another one-off, let's set flatten_list on buildSettings properties
+ # of XCBuildConfiguration objects, because that's how Xcode treats them.
+ if key == 'buildSettings' and isinstance(self, XCBuildConfiguration):
+ flatten_list = True
+ else:
+ flatten_list = False
+
+ try:
+ printable_key = self._XCPrintableValue(tabs, key, flatten_list)
+ printable_value = self._XCPrintableValue(tabs, value_to_print,
+ flatten_list)
+ if strip_value_quotes and len(printable_value) > 1 and \
+ printable_value[0] == '"' and printable_value[-1] == '"':
+ printable_value = printable_value[1:-1]
+ printable += printable_key + ' = ' + printable_value + ';' + after_kv
+ except TypeError, e:
+ gyp.common.ExceptionAppend(e,
+ 'while printing key "%s"' % key)
+ raise
+
+ self._XCPrint(file, 0, printable)
+
+ def Print(self, file=sys.stdout):
+ """Prints a reprentation of this object to file, adhering to Xcode output
+ formatting.
+ """
+
+ self.VerifyHasRequiredProperties()
+
+ if self._should_print_single_line:
+ # When printing an object in a single line, Xcode doesn't put any space
+ # between the beginning of a dictionary (or presumably a list) and the
+ # first contained item, so you wind up with snippets like
+ # ...CDEF = {isa = PBXFileReference; fileRef = 0123...
+ # If it were me, I would have put a space in there after the opening
+ # curly, but I guess this is just another one of those inconsistencies
+ # between how Xcode prints PBXFileReference and PBXBuildFile objects as
+ # compared to other objects. Mimic Xcode's behavior here by using an
+ # empty string for sep.
+ sep = ''
+ end_tabs = 0
+ else:
+ sep = '\n'
+ end_tabs = 2
+
+ # Start the object. For example, '\t\tPBXProject = {\n'.
+ self._XCPrint(file, 2, self._XCPrintableValue(2, self) + ' = {' + sep)
+
+ # "isa" isn't in the _properties dictionary, it's an intrinsic property
+ # of the class which the object belongs to. Xcode always outputs "isa"
+ # as the first element of an object dictionary.
+ self._XCKVPrint(file, 3, 'isa', self.__class__.__name__)
+
+ # The remaining elements of an object dictionary are sorted alphabetically.
+ for property, value in sorted(self._properties.iteritems()):
+ self._XCKVPrint(file, 3, property, value)
+
+ # End the object.
+ self._XCPrint(file, end_tabs, '};\n')
+
+ def UpdateProperties(self, properties, do_copy=False):
+ """Merge the supplied properties into the _properties dictionary.
+
+ The input properties must adhere to the class schema or a KeyError or
+ TypeError exception will be raised. If adding an object of an XCObject
+ subclass and the schema indicates a strong relationship, the object's
+ parent will be set to this object.
+
+ If do_copy is True, then lists, dicts, strong-owned XCObjects, and
+ strong-owned XCObjects in lists will be copied instead of having their
+ references added.
+ """
+
+ if properties == None:
+ return
+
+ for property, value in properties.iteritems():
+ # Make sure the property is in the schema.
+ if not property in self._schema:
+ raise KeyError, property + ' not in ' + self.__class__.__name__
+
+ # Make sure the property conforms to the schema.
+ (is_list, property_type, is_strong) = self._schema[property][0:3]
+ if is_list:
+ if value.__class__ != list:
+ raise TypeError, \
+ property + ' of ' + self.__class__.__name__ + \
+ ' must be list, not ' + value.__class__.__name__
+ for item in value:
+ if not isinstance(item, property_type) and \
+ not (item.__class__ == unicode and property_type == str):
+ # Accept unicode where str is specified. str is treated as
+ # UTF-8-encoded.
+ raise TypeError, \
+ 'item of ' + property + ' of ' + self.__class__.__name__ + \
+ ' must be ' + property_type.__name__ + ', not ' + \
+ item.__class__.__name__
+ elif not isinstance(value, property_type) and \
+ not (value.__class__ == unicode and property_type == str):
+ # Accept unicode where str is specified. str is treated as
+ # UTF-8-encoded.
+ raise TypeError, \
+ property + ' of ' + self.__class__.__name__ + ' must be ' + \
+ property_type.__name__ + ', not ' + value.__class__.__name__
+
+ # Checks passed, perform the assignment.
+ if do_copy:
+ if isinstance(value, XCObject):
+ if is_strong:
+ self._properties[property] = value.Copy()
+ else:
+ self._properties[property] = value
+ elif isinstance(value, str) or isinstance(value, unicode) or \
+ isinstance(value, int):
+ self._properties[property] = value
+ elif isinstance(value, list):
+ if is_strong:
+ # If is_strong is True, each element is an XCObject, so it's safe
+ # to call Copy.
+ self._properties[property] = []
+ for item in value:
+ self._properties[property].append(item.Copy())
+ else:
+ self._properties[property] = value[:]
+ elif isinstance(value, dict):
+ self._properties[property] = value.copy()
+ else:
+ raise TypeError, "Don't know how to copy a " + \
+ value.__class__.__name__ + ' object for ' + \
+ property + ' in ' + self.__class__.__name__
+ else:
+ self._properties[property] = value
+
+ # Set up the child's back-reference to this object. Don't use |value|
+ # any more because it may not be right if do_copy is true.
+ if is_strong:
+ if not is_list:
+ self._properties[property].parent = self
+ else:
+ for item in self._properties[property]:
+ item.parent = self
+
+ def HasProperty(self, key):
+ return key in self._properties
+
+ def GetProperty(self, key):
+ return self._properties[key]
+
+ def SetProperty(self, key, value):
+ self.UpdateProperties({key: value})
+
+ def DelProperty(self, key):
+ if key in self._properties:
+ del self._properties[key]
+
+ def AppendProperty(self, key, value):
+ # TODO(mark): Support ExtendProperty too (and make this call that)?
+
+ # Schema validation.
+ if not key in self._schema:
+ raise KeyError, key + ' not in ' + self.__class__.__name__
+
+ (is_list, property_type, is_strong) = self._schema[key][0:3]
+ if not is_list:
+ raise TypeError, key + ' of ' + self.__class__.__name__ + ' must be list'
+ if not isinstance(value, property_type):
+ raise TypeError, 'item of ' + key + ' of ' + self.__class__.__name__ + \
+ ' must be ' + property_type.__name__ + ', not ' + \
+ value.__class__.__name__
+
+ # If the property doesn't exist yet, create a new empty list to receive the
+ # item.
+ if not key in self._properties:
+ self._properties[key] = []
+
+ # Set up the ownership link.
+ if is_strong:
+ value.parent = self
+
+ # Store the item.
+ self._properties[key].append(value)
+
+ def VerifyHasRequiredProperties(self):
+ """Ensure that all properties identified as required by the schema are
+ set.
+ """
+
+ # TODO(mark): A stronger verification mechanism is needed. Some
+ # subclasses need to perform validation beyond what the schema can enforce.
+ for property, attributes in self._schema.iteritems():
+ (is_list, property_type, is_strong, is_required) = attributes[0:4]
+ if is_required and not property in self._properties:
+ raise KeyError, self.__class__.__name__ + ' requires ' + property
+
+ def _SetDefaultsFromSchema(self):
+ """Assign object default values according to the schema. This will not
+ overwrite properties that have already been set."""
+
+ defaults = {}
+ for property, attributes in self._schema.iteritems():
+ (is_list, property_type, is_strong, is_required) = attributes[0:4]
+ if is_required and len(attributes) >= 5 and \
+ not property in self._properties:
+ default = attributes[4]
+
+ defaults[property] = default
+
+ if len(defaults) > 0:
+ # Use do_copy=True so that each new object gets its own copy of strong
+ # objects, lists, and dicts.
+ self.UpdateProperties(defaults, do_copy=True)
+
+
+class XCHierarchicalElement(XCObject):
+ """Abstract base for PBXGroup and PBXFileReference. Not represented in a
+ project file."""
+
+ # TODO(mark): Do name and path belong here? Probably so.
+ # If path is set and name is not, name may have a default value. Name will
+ # be set to the basename of path, if the basename of path is different from
+ # the full value of path. If path is already just a leaf name, name will
+ # not be set.
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'comments': [0, str, 0, 0],
+ 'fileEncoding': [0, str, 0, 0],
+ 'includeInIndex': [0, int, 0, 0],
+ 'indentWidth': [0, int, 0, 0],
+ 'lineEnding': [0, int, 0, 0],
+ 'sourceTree': [0, str, 0, 1, '<group>'],
+ 'tabWidth': [0, int, 0, 0],
+ 'usesTabs': [0, int, 0, 0],
+ 'wrapsLines': [0, int, 0, 0],
+ })
+
+ def __init__(self, properties=None, id=None, parent=None):
+ # super
+ XCObject.__init__(self, properties, id, parent)
+ if 'path' in self._properties and not 'name' in self._properties:
+ path = self._properties['path']
+ name = posixpath.basename(path)
+ if name != '' and path != name:
+ self.SetProperty('name', name)
+
+ if 'path' in self._properties and \
+ (not 'sourceTree' in self._properties or \
+ self._properties['sourceTree'] == '<group>'):
+ # If the pathname begins with an Xcode variable like "$(SDKROOT)/", take
+ # the variable out and make the path be relative to that variable by
+ # assigning the variable name as the sourceTree.
+ (source_tree, path) = SourceTreeAndPathFromPath(self._properties['path'])
+ if source_tree != None:
+ self._properties['sourceTree'] = source_tree
+ if path != None:
+ self._properties['path'] = path
+ if source_tree != None and path == None and \
+ not 'name' in self._properties:
+ # The path was of the form "$(SDKROOT)" with no path following it.
+ # This object is now relative to that variable, so it has no path
+ # attribute of its own. It does, however, keep a name.
+ del self._properties['path']
+ self._properties['name'] = source_tree
+
+ def Name(self):
+ if 'name' in self._properties:
+ return self._properties['name']
+ elif 'path' in self._properties:
+ return self._properties['path']
+ else:
+ # This happens in the case of the root PBXGroup.
+ return None
+
+ def Hashables(self):
+ """Custom hashables for XCHierarchicalElements.
+
+ XCHierarchicalElements are special. Generally, their hashes shouldn't
+ change if the paths don't change. The normal XCObject implementation of
+ Hashables adds a hashable for each object, which means that if
+ the hierarchical structure changes (possibly due to changes caused when
+ TakeOverOnlyChild runs and encounters slight changes in the hierarchy),
+ the hashes will change. For example, if a project file initially contains
+ a/b/f1 and a/b becomes collapsed into a/b, f1 will have a single parent
+ a/b. If someone later adds a/f2 to the project file, a/b can no longer be
+ collapsed, and f1 winds up with parent b and grandparent a. That would
+ be sufficient to change f1's hash.
+
+ To counteract this problem, hashables for all XCHierarchicalElements except
+ for the main group (which has neither a name nor a path) are taken to be
+ just the set of path components. Because hashables are inherited from
+ parents, this provides assurance that a/b/f1 has the same set of hashables
+ whether its parent is b or a/b.
+
+ The main group is a special case. As it is permitted to have no name or
+ path, it is permitted to use the standard XCObject hash mechanism. This
+ is not considered a problem because there can be only one main group.
+ """
+
+ if self == self.PBXProjectAncestor()._properties['mainGroup']:
+ # super
+ return XCObject.Hashables(self)
+
+ hashables = []
+
+ # Put the name in first, ensuring that if TakeOverOnlyChild collapses
+ # children into a top-level group like "Source", the name always goes
+ # into the list of hashables without interfering with path components.
+ if 'name' in self._properties:
+ # Make it less likely for people to manipulate hashes by following the
+ # pattern of always pushing an object type value onto the list first.
+ hashables.append(self.__class__.__name__ + '.name')
+ hashables.append(self._properties['name'])
+
+ # NOTE: This still has the problem that if an absolute path is encountered,
+ # including paths with a sourceTree, they'll still inherit their parents'
+ # hashables, even though the paths aren't relative to their parents. This
+ # is not expected to be much of a problem in practice.
+ path = self.PathFromSourceTreeAndPath()
+ if path != None:
+ components = path.split(posixpath.sep)
+ for component in components:
+ hashables.append(self.__class__.__name__ + '.path')
+ hashables.append(component)
+
+ hashables.extend(self._hashables)
+
+ return hashables
+
+ def Compare(self, other):
+ # Allow comparison of these types. PBXGroup has the highest sort rank;
+ # PBXVariantGroup is treated as equal to PBXFileReference.
+ valid_class_types = {
+ PBXFileReference: 'file',
+ PBXGroup: 'group',
+ PBXVariantGroup: 'file',
+ }
+ self_type = valid_class_types[self.__class__]
+ other_type = valid_class_types[other.__class__]
+
+ if self_type == other_type:
+ # If the two objects are of the same sort rank, compare their names.
+ return cmp(self.Name(), other.Name())
+
+ # Otherwise, sort groups before everything else.
+ if self_type == 'group':
+ return -1
+ return 1
+
+ def CompareRootGroup(self, other):
+ # This function should be used only to compare direct children of the
+ # containing PBXProject's mainGroup. These groups should appear in the
+ # listed order.
+ # TODO(mark): "Build" is used by gyp.generator.xcode, perhaps the
+ # generator should have a way of influencing this list rather than having
+ # to hardcode for the generator here.
+ order = ['Source', 'Intermediates', 'Projects', 'Frameworks', 'Products',
+ 'Build']
+
+ # If the groups aren't in the listed order, do a name comparison.
+ # Otherwise, groups in the listed order should come before those that
+ # aren't.
+ self_name = self.Name()
+ other_name = other.Name()
+ self_in = isinstance(self, PBXGroup) and self_name in order
+ other_in = isinstance(self, PBXGroup) and other_name in order
+ if not self_in and not other_in:
+ return self.Compare(other)
+ if self_name in order and not other_name in order:
+ return -1
+ if other_name in order and not self_name in order:
+ return 1
+
+ # If both groups are in the listed order, go by the defined order.
+ self_index = order.index(self_name)
+ other_index = order.index(other_name)
+ if self_index < other_index:
+ return -1
+ if self_index > other_index:
+ return 1
+ return 0
+
+ def PathFromSourceTreeAndPath(self):
+ # Turn the object's sourceTree and path properties into a single flat
+ # string of a form comparable to the path parameter. If there's a
+ # sourceTree property other than "<group>", wrap it in $(...) for the
+ # comparison.
+ components = []
+ if self._properties['sourceTree'] != '<group>':
+ components.append('$(' + self._properties['sourceTree'] + ')')
+ if 'path' in self._properties:
+ components.append(self._properties['path'])
+
+ if len(components) > 0:
+ return posixpath.join(*components)
+
+ return None
+
+ def FullPath(self):
+ # Returns a full path to self relative to the project file, or relative
+ # to some other source tree. Start with self, and walk up the chain of
+ # parents prepending their paths, if any, until no more parents are
+ # available (project-relative path) or until a path relative to some
+ # source tree is found.
+ xche = self
+ path = None
+ while isinstance(xche, XCHierarchicalElement) and \
+ (path == None or \
+ (not path.startswith('/') and not path.startswith('$'))):
+ this_path = xche.PathFromSourceTreeAndPath()
+ if this_path != None and path != None:
+ path = posixpath.join(this_path, path)
+ elif this_path != None:
+ path = this_path
+ xche = xche.parent
+
+ return path
+
+
+class PBXGroup(XCHierarchicalElement):
+ """
+ Attributes:
+ _children_by_path: Maps pathnames of children of this PBXGroup to the
+ actual child XCHierarchicalElement objects.
+ _variant_children_by_name_and_path: Maps (name, path) tuples of
+ PBXVariantGroup children to the actual child PBXVariantGroup objects.
+ """
+
+ _schema = XCHierarchicalElement._schema.copy()
+ _schema.update({
+ 'children': [1, XCHierarchicalElement, 1, 1, []],
+ 'name': [0, str, 0, 0],
+ 'path': [0, str, 0, 0],
+ })
+
+ def __init__(self, properties=None, id=None, parent=None):
+ # super
+ XCHierarchicalElement.__init__(self, properties, id, parent)
+ self._children_by_path = {}
+ self._variant_children_by_name_and_path = {}
+ for child in self._properties.get('children', []):
+ self._AddChildToDicts(child)
+
+ def _AddChildToDicts(self, child):
+ # Sets up this PBXGroup object's dicts to reference the child properly.
+ child_path = child.PathFromSourceTreeAndPath()
+ if child_path:
+ if child_path in self._children_by_path:
+ raise ValueError, 'Found multiple children with path ' + child_path
+ self._children_by_path[child_path] = child
+
+ if isinstance(child, PBXVariantGroup):
+ child_name = child._properties.get('name', None)
+ key = (child_name, child_path)
+ if key in self._variant_children_by_name_and_path:
+ raise ValueError, 'Found multiple PBXVariantGroup children with ' + \
+ 'name ' + str(child_name) + ' and path ' + \
+ str(child_path)
+ self._variant_children_by_name_and_path[key] = child
+
+ def AppendChild(self, child):
+ # Callers should use this instead of calling
+ # AppendProperty('children', child) directly because this function
+ # maintains the group's dicts.
+ self.AppendProperty('children', child)
+ self._AddChildToDicts(child)
+
+ def GetChildByName(self, name):
+ # This is not currently optimized with a dict as GetChildByPath is because
+ # it has few callers. Most callers probably want GetChildByPath. This
+ # function is only useful to get children that have names but no paths,
+ # which is rare. The children of the main group ("Source", "Products",
+ # etc.) is pretty much the only case where this likely to come up.
+ #
+ # TODO(mark): Maybe this should raise an error if more than one child is
+ # present with the same name.
+ if not 'children' in self._properties:
+ return None
+
+ for child in self._properties['children']:
+ if child.Name() == name:
+ return child
+
+ return None
+
+ def GetChildByPath(self, path):
+ if not path:
+ return None
+
+ if path in self._children_by_path:
+ return self._children_by_path[path]
+
+ return None
+
+ def GetChildByRemoteObject(self, remote_object):
+ # This method is a little bit esoteric. Given a remote_object, which
+ # should be a PBXFileReference in another project file, this method will
+ # return this group's PBXReferenceProxy object serving as a local proxy
+ # for the remote PBXFileReference.
+ #
+ # This function might benefit from a dict optimization as GetChildByPath
+ # for some workloads, but profiling shows that it's not currently a
+ # problem.
+ if not 'children' in self._properties:
+ return None
+
+ for child in self._properties['children']:
+ if not isinstance(child, PBXReferenceProxy):
+ continue
+
+ container_proxy = child._properties['remoteRef']
+ if container_proxy._properties['remoteGlobalIDString'] == remote_object:
+ return child
+
+ return None
+
+ def AddOrGetFileByPath(self, path, hierarchical):
+ """Returns an existing or new file reference corresponding to path.
+
+ If hierarchical is True, this method will create or use the necessary
+ hierarchical group structure corresponding to path. Otherwise, it will
+ look in and create an item in the current group only.
+
+ If an existing matching reference is found, it is returned, otherwise, a
+ new one will be created, added to the correct group, and returned.
+
+ If path identifies a directory by virtue of carrying a trailing slash,
+ this method returns a PBXFileReference of "folder" type. If path
+ identifies a variant, by virtue of it identifying a file inside a directory
+ with an ".lproj" extension, this method returns a PBXVariantGroup
+ containing the variant named by path, and possibly other variants. For
+ all other paths, a "normal" PBXFileReference will be returned.
+ """
+
+ # Adding or getting a directory? Directories end with a trailing slash.
+ is_dir = False
+ if path.endswith('/'):
+ is_dir = True
+ normpath = posixpath.normpath(path)
+ if is_dir:
+ normpath = path + '/'
+ else:
+ normpath = path
+
+ # Adding or getting a variant? Variants are files inside directories
+ # with an ".lproj" extension. Xcode uses variants for localization. For
+ # a variant path/to/Language.lproj/MainMenu.nib, put a variant group named
+ # MainMenu.nib inside path/to, and give it a variant named Language. In
+ # this example, grandparent would be set to path/to and parent_root would
+ # be set to Language.
+ variant_name = None
+ parent = posixpath.dirname(path)
+ grandparent = posixpath.dirname(parent)
+ parent_basename = posixpath.basename(parent)
+ (parent_root, parent_ext) = posixpath.splitext(parent_basename)
+ if parent_ext == '.lproj':
+ variant_name = parent_root
+ if grandparent == '':
+ grandparent = None
+
+ # Putting a directory inside a variant group is not currently supported.
+ assert not is_dir or variant_name == None
+
+ path_split = path.split(posixpath.sep)
+ if len(path_split) == 1 or \
+ ((is_dir or variant_name != None) and len(path_split) == 2) or \
+ not hierarchical:
+ # The PBXFileReference or PBXVariantGroup will be added to or gotten from
+ # this PBXGroup, no recursion necessary.
+ if variant_name == None:
+ # Add or get a PBXFileReference.
+ file_ref = self.GetChildByPath(normpath)
+ if file_ref != None:
+ assert file_ref.__class__ == PBXFileReference
+ else:
+ file_ref = PBXFileReference({'path': path})
+ self.AppendChild(file_ref)
+ else:
+ # Add or get a PBXVariantGroup. The variant group name is the same
+ # as the basename (MainMenu.nib in the example above). grandparent
+ # specifies the path to the variant group itself, and path_split[-2:]
+ # is the path of the specific variant relative to its group.
+ variant_group_name = posixpath.basename(path)
+ variant_group_ref = self.AddOrGetVariantGroupByNameAndPath(
+ variant_group_name, grandparent)
+ variant_path = posixpath.sep.join(path_split[-2:])
+ variant_ref = variant_group_ref.GetChildByPath(variant_path)
+ if variant_ref != None:
+ assert variant_ref.__class__ == PBXFileReference
+ else:
+ variant_ref = PBXFileReference({'name': variant_name,
+ 'path': variant_path})
+ variant_group_ref.AppendChild(variant_ref)
+ # The caller is interested in the variant group, not the specific
+ # variant file.
+ file_ref = variant_group_ref
+ return file_ref
+ else:
+ # Hierarchical recursion. Add or get a PBXGroup corresponding to the
+ # outermost path component, and then recurse into it, chopping off that
+ # path component.
+ next_dir = path_split[0]
+ group_ref = self.GetChildByPath(next_dir)
+ if group_ref != None:
+ assert group_ref.__class__ == PBXGroup
+ else:
+ group_ref = PBXGroup({'path': next_dir})
+ self.AppendChild(group_ref)
+ return group_ref.AddOrGetFileByPath(posixpath.sep.join(path_split[1:]),
+ hierarchical)
+
+ def AddOrGetVariantGroupByNameAndPath(self, name, path):
+ """Returns an existing or new PBXVariantGroup for name and path.
+
+ If a PBXVariantGroup identified by the name and path arguments is already
+ present as a child of this object, it is returned. Otherwise, a new
+ PBXVariantGroup with the correct properties is created, added as a child,
+ and returned.
+
+ This method will generally be called by AddOrGetFileByPath, which knows
+ when to create a variant group based on the structure of the pathnames
+ passed to it.
+ """
+
+ key = (name, path)
+ if key in self._variant_children_by_name_and_path:
+ variant_group_ref = self._variant_children_by_name_and_path[key]
+ assert variant_group_ref.__class__ == PBXVariantGroup
+ return variant_group_ref
+
+ variant_group_properties = {'name': name}
+ if path != None:
+ variant_group_properties['path'] = path
+ variant_group_ref = PBXVariantGroup(variant_group_properties)
+ self.AppendChild(variant_group_ref)
+
+ return variant_group_ref
+
+ def TakeOverOnlyChild(self, recurse=False):
+ """If this PBXGroup has only one child and it's also a PBXGroup, take
+ it over by making all of its children this object's children.
+
+ This function will continue to take over only children when those children
+ are groups. If there are three PBXGroups representing a, b, and c, with
+ c inside b and b inside a, and a and b have no other children, this will
+ result in a taking over both b and c, forming a PBXGroup for a/b/c.
+
+ If recurse is True, this function will recurse into children and ask them
+ to collapse themselves by taking over only children as well. Assuming
+ an example hierarchy with files at a/b/c/d1, a/b/c/d2, and a/b/c/d3/e/f
+ (d1, d2, and f are files, the rest are groups), recursion will result in
+ a group for a/b/c containing a group for d3/e.
+ """
+
+ # At this stage, check that child class types are PBXGroup exactly,
+ # instead of using isinstance. The only subclass of PBXGroup,
+ # PBXVariantGroup, should not participate in reparenting in the same way:
+ # reparenting by merging different object types would be wrong.
+ while len(self._properties['children']) == 1 and \
+ self._properties['children'][0].__class__ == PBXGroup:
+ # Loop to take over the innermost only-child group possible.
+
+ child = self._properties['children'][0]
+
+ # Assume the child's properties, including its children. Save a copy
+ # of this object's old properties, because they'll still be needed.
+ # This object retains its existing id and parent attributes.
+ old_properties = self._properties
+ self._properties = child._properties
+ self._children_by_path = child._children_by_path
+
+ if not 'sourceTree' in self._properties or \
+ self._properties['sourceTree'] == '<group>':
+ # The child was relative to its parent. Fix up the path. Note that
+ # children with a sourceTree other than "<group>" are not relative to
+ # their parents, so no path fix-up is needed in that case.
+ if 'path' in old_properties:
+ if 'path' in self._properties:
+ # Both the original parent and child have paths set.
+ self._properties['path'] = posixpath.join(old_properties['path'],
+ self._properties['path'])
+ else:
+ # Only the original parent has a path, use it.
+ self._properties['path'] = old_properties['path']
+ if 'sourceTree' in old_properties:
+ # The original parent had a sourceTree set, use it.
+ self._properties['sourceTree'] = old_properties['sourceTree']
+
+ # If the original parent had a name set, keep using it. If the original
+ # parent didn't have a name but the child did, let the child's name
+ # live on. If the name attribute seems unnecessary now, get rid of it.
+ if 'name' in old_properties and old_properties['name'] != None and \
+ old_properties['name'] != self.Name():
+ self._properties['name'] = old_properties['name']
+ if 'name' in self._properties and 'path' in self._properties and \
+ self._properties['name'] == self._properties['path']:
+ del self._properties['name']
+
+ # Notify all children of their new parent.
+ for child in self._properties['children']:
+ child.parent = self
+
+ # If asked to recurse, recurse.
+ if recurse:
+ for child in self._properties['children']:
+ if child.__class__ == PBXGroup:
+ child.TakeOverOnlyChild(recurse)
+
+ def SortGroup(self):
+ self._properties['children'] = \
+ sorted(self._properties['children'], cmp=lambda x,y: x.Compare(y))
+
+ # Recurse.
+ for child in self._properties['children']:
+ if isinstance(child, PBXGroup):
+ child.SortGroup()
+
+
+class XCFileLikeElement(XCHierarchicalElement):
+ # Abstract base for objects that can be used as the fileRef property of
+ # PBXBuildFile.
+
+ def PathHashables(self):
+ # A PBXBuildFile that refers to this object will call this method to
+ # obtain additional hashables specific to this XCFileLikeElement. Don't
+ # just use this object's hashables, they're not specific and unique enough
+ # on their own (without access to the parent hashables.) Instead, provide
+ # hashables that identify this object by path by getting its hashables as
+ # well as the hashables of ancestor XCHierarchicalElement objects.
+
+ hashables = []
+ xche = self
+ while xche != None and isinstance(xche, XCHierarchicalElement):
+ xche_hashables = xche.Hashables()
+ for index in xrange(0, len(xche_hashables)):
+ hashables.insert(index, xche_hashables[index])
+ xche = xche.parent
+ return hashables
+
+
+class XCContainerPortal(XCObject):
+ # Abstract base for objects that can be used as the containerPortal property
+ # of PBXContainerItemProxy.
+ pass
+
+
+class XCRemoteObject(XCObject):
+ # Abstract base for objects that can be used as the remoteGlobalIDString
+ # property of PBXContainerItemProxy.
+ pass
+
+
+class PBXFileReference(XCFileLikeElement, XCContainerPortal, XCRemoteObject):
+ _schema = XCFileLikeElement._schema.copy()
+ _schema.update({
+ 'explicitFileType': [0, str, 0, 0],
+ 'lastKnownFileType': [0, str, 0, 0],
+ 'name': [0, str, 0, 0],
+ 'path': [0, str, 0, 1],
+ })
+
+ # Weird output rules for PBXFileReference.
+ _should_print_single_line = True
+ # super
+ _encode_transforms = XCFileLikeElement._alternate_encode_transforms
+
+ def __init__(self, properties=None, id=None, parent=None):
+ # super
+ XCFileLikeElement.__init__(self, properties, id, parent)
+ if 'path' in self._properties and self._properties['path'].endswith('/'):
+ self._properties['path'] = self._properties['path'][:-1]
+ is_dir = True
+ else:
+ is_dir = False
+
+ if 'path' in self._properties and \
+ not 'lastKnownFileType' in self._properties and \
+ not 'explicitFileType' in self._properties:
+ # TODO(mark): This is the replacement for a replacement for a quick hack.
+ # It is no longer incredibly sucky, but this list needs to be extended.
+ extension_map = {
+ 'a': 'archive.ar',
+ 'app': 'wrapper.application',
+ 'bdic': 'file',
+ 'bundle': 'wrapper.cfbundle',
+ 'c': 'sourcecode.c.c',
+ 'cc': 'sourcecode.cpp.cpp',
+ 'cpp': 'sourcecode.cpp.cpp',
+ 'css': 'text.css',
+ 'cxx': 'sourcecode.cpp.cpp',
+ 'dylib': 'compiled.mach-o.dylib',
+ 'framework': 'wrapper.framework',
+ 'h': 'sourcecode.c.h',
+ 'hxx': 'sourcecode.cpp.h',
+ 'icns': 'image.icns',
+ 'java': 'sourcecode.java',
+ 'js': 'sourcecode.javascript',
+ 'm': 'sourcecode.c.objc',
+ 'mm': 'sourcecode.cpp.objcpp',
+ 'nib': 'wrapper.nib',
+ 'o': 'compiled.mach-o.objfile',
+ 'pdf': 'image.pdf',
+ 'pl': 'text.script.perl',
+ 'plist': 'text.plist.xml',
+ 'pm': 'text.script.perl',
+ 'png': 'image.png',
+ 'py': 'text.script.python',
+ 'r': 'sourcecode.rez',
+ 'rez': 'sourcecode.rez',
+ 's': 'sourcecode.asm',
+ 'strings': 'text.plist.strings',
+ 'ttf': 'file',
+ 'xcconfig': 'text.xcconfig',
+ 'xib': 'file.xib',
+ 'y': 'sourcecode.yacc',
+ }
+
+ if is_dir:
+ file_type = 'folder'
+ else:
+ basename = posixpath.basename(self._properties['path'])
+ (root, ext) = posixpath.splitext(basename)
+ # Check the map using a lowercase extension.
+ # TODO(mark): Maybe it should try with the original case first and fall
+ # back to lowercase, in case there are any instances where case
+ # matters. There currently aren't.
+ if ext != '':
+ ext = ext[1:].lower()
+
+ # TODO(mark): "text" is the default value, but "file" is appropriate
+ # for unrecognized files not containing text. Xcode seems to choose
+ # based on content.
+ file_type = extension_map.get(ext, 'text')
+
+ self._properties['lastKnownFileType'] = file_type
+
+
+class PBXVariantGroup(PBXGroup, XCFileLikeElement):
+ """PBXVariantGroup is used by Xcode to represent localizations."""
+ # No additions to the schema relative to PBXGroup.
+ pass
+
+
+# PBXReferenceProxy is also an XCFileLikeElement subclass. It is defined below
+# because it uses PBXContainerItemProxy, defined below.
+
+
+class XCBuildConfiguration(XCObject):
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'baseConfigurationReference': [0, PBXFileReference, 0, 0],
+ 'buildSettings': [0, dict, 0, 1, {}],
+ 'name': [0, str, 0, 1],
+ })
+
+ def HasBuildSetting(self, key):
+ return key in self._properties['buildSettings']
+
+ def GetBuildSetting(self, key):
+ return self._properties['buildSettings'][key]
+
+ def SetBuildSetting(self, key, value):
+ # TODO(mark): If a list, copy?
+ self._properties['buildSettings'][key] = value
+
+ def AppendBuildSetting(self, key, value):
+ if not key in self._properties['buildSettings']:
+ self._properties['buildSettings'][key] = []
+ self._properties['buildSettings'][key].append(value)
+
+ def DelBuildSetting(self, key):
+ if key in self._properties['buildSettings']:
+ del self._properties['buildSettings'][key]
+
+ def SetBaseConfiguration(self, value):
+ self._properties['baseConfigurationReference'] = value
+
+class XCConfigurationList(XCObject):
+ # _configs is the default list of configurations.
+ _configs = [ XCBuildConfiguration({'name': 'Debug'}),
+ XCBuildConfiguration({'name': 'Release'}) ]
+
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'buildConfigurations': [1, XCBuildConfiguration, 1, 1, _configs],
+ 'defaultConfigurationIsVisible': [0, int, 0, 1, 1],
+ 'defaultConfigurationName': [0, str, 0, 1, 'Release'],
+ })
+
+ def Name(self):
+ return 'Build configuration list for ' + \
+ self.parent.__class__.__name__ + ' "' + self.parent.Name() + '"'
+
+ def ConfigurationNamed(self, name):
+ """Convenience accessor to obtain an XCBuildConfiguration by name."""
+ for configuration in self._properties['buildConfigurations']:
+ if configuration._properties['name'] == name:
+ return configuration
+
+ raise KeyError, name
+
+ def DefaultConfiguration(self):
+ """Convenience accessor to obtain the default XCBuildConfiguration."""
+ return self.ConfigurationNamed(self._properties['defaultConfigurationName'])
+
+ def HasBuildSetting(self, key):
+ """Determines the state of a build setting in all XCBuildConfiguration
+ child objects.
+
+ If all child objects have key in their build settings, and the value is the
+ same in all child objects, returns 1.
+
+ If no child objects have the key in their build settings, returns 0.
+
+ If some, but not all, child objects have the key in their build settings,
+ or if any children have different values for the key, returns -1.
+ """
+
+ has = None
+ value = None
+ for configuration in self._properties['buildConfigurations']:
+ configuration_has = configuration.HasBuildSetting(key)
+ if has == None:
+ has = configuration_has
+ elif has != configuration_has:
+ return -1
+
+ if configuration_has:
+ configuration_value = configuration.GetBuildSetting(key)
+ if value == None:
+ value = configuration_value
+ elif value != configuration_value:
+ return -1
+
+ if not has:
+ return 0
+
+ return 1
+
+ def GetBuildSetting(self, key):
+ """Gets the build setting for key.
+
+ All child XCConfiguration objects must have the same value set for the
+ setting, or a ValueError will be raised.
+ """
+
+ # TODO(mark): This is wrong for build settings that are lists. The list
+ # contents should be compared (and a list copy returned?)
+
+ value = None
+ for configuration in self._properties['buildConfigurations']:
+ configuration_value = configuration.GetBuildSetting(key)
+ if value == None:
+ value = configuration_value
+ else:
+ if value != configuration_value:
+ raise ValueError, 'Variant values for ' + key
+
+ return value
+
+ def SetBuildSetting(self, key, value):
+ """Sets the build setting for key to value in all child
+ XCBuildConfiguration objects.
+ """
+
+ for configuration in self._properties['buildConfigurations']:
+ configuration.SetBuildSetting(key, value)
+
+ def AppendBuildSetting(self, key, value):
+ """Appends value to the build setting for key, which is treated as a list,
+ in all child XCBuildConfiguration objects.
+ """
+
+ for configuration in self._properties['buildConfigurations']:
+ configuration.AppendBuildSetting(key, value)
+
+ def DelBuildSetting(self, key):
+ """Deletes the build setting key from all child XCBuildConfiguration
+ objects.
+ """
+
+ for configuration in self._properties['buildConfigurations']:
+ configuration.DelBuildSetting(key)
+
+ def SetBaseConfiguration(self, value):
+ """Sets the build configuration in all child XCBuildConfiguration objects.
+ """
+
+ for configuration in self._properties['buildConfigurations']:
+ configuration.SetBaseConfiguration(value)
+
+
+class PBXBuildFile(XCObject):
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'fileRef': [0, XCFileLikeElement, 0, 1],
+ 'settings': [0, str, 0, 0], # hack, it's a dict
+ })
+
+ # Weird output rules for PBXBuildFile.
+ _should_print_single_line = True
+ _encode_transforms = XCObject._alternate_encode_transforms
+
+ def Name(self):
+ # Example: "main.cc in Sources"
+ return self._properties['fileRef'].Name() + ' in ' + self.parent.Name()
+
+ def Hashables(self):
+ # super
+ hashables = XCObject.Hashables(self)
+
+ # It is not sufficient to just rely on Name() to get the
+ # XCFileLikeElement's name, because that is not a complete pathname.
+ # PathHashables returns hashables unique enough that no two
+ # PBXBuildFiles should wind up with the same set of hashables, unless
+ # someone adds the same file multiple times to the same target. That
+ # would be considered invalid anyway.
+ hashables.extend(self._properties['fileRef'].PathHashables())
+
+ return hashables
+
+
+class XCBuildPhase(XCObject):
+ """Abstract base for build phase classes. Not represented in a project
+ file.
+
+ Attributes:
+ _files_by_path: A dict mapping each path of a child in the files list by
+ path (keys) to the corresponding PBXBuildFile children (values).
+ _files_by_xcfilelikeelement: A dict mapping each XCFileLikeElement (keys)
+ to the corresponding PBXBuildFile children (values).
+ """
+
+ # TODO(mark): Some build phase types, like PBXShellScriptBuildPhase, don't
+ # actually have a "files" list. XCBuildPhase should not have "files" but
+ # another abstract subclass of it should provide this, and concrete build
+ # phase types that do have "files" lists should be derived from that new
+ # abstract subclass. XCBuildPhase should only provide buildActionMask and
+ # runOnlyForDeploymentPostprocessing, and not files or the various
+ # file-related methods and attributes.
+
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'buildActionMask': [0, int, 0, 1, 0x7fffffff],
+ 'files': [1, PBXBuildFile, 1, 1, []],
+ 'runOnlyForDeploymentPostprocessing': [0, int, 0, 1, 0],
+ })
+
+ def __init__(self, properties=None, id=None, parent=None):
+ # super
+ XCObject.__init__(self, properties, id, parent)
+
+ self._files_by_path = {}
+ self._files_by_xcfilelikeelement = {}
+ for pbxbuildfile in self._properties.get('files', []):
+ self._AddBuildFileToDicts(pbxbuildfile)
+
+ def FileGroup(self, path):
+ # Subclasses must override this by returning a two-element tuple. The
+ # first item in the tuple should be the PBXGroup to which "path" should be
+ # added, either as a child or deeper descendant. The second item should
+ # be a boolean indicating whether files should be added into hierarchical
+ # groups or one single flat group.
+ raise NotImplementedError, \
+ self.__class__.__name__ + ' must implement FileGroup'
+
+ def _AddPathToDict(self, pbxbuildfile, path):
+ """Adds path to the dict tracking paths belonging to this build phase.
+
+ If the path is already a member of this build phase, raises an exception.
+ """
+
+ if path in self._files_by_path:
+ raise ValueError, 'Found multiple build files with path ' + path
+ self._files_by_path[path] = pbxbuildfile
+
+ def _AddBuildFileToDicts(self, pbxbuildfile, path=None):
+ """Maintains the _files_by_path and _files_by_xcfilelikeelement dicts.
+
+ If path is specified, then it is the path that is being added to the
+ phase, and pbxbuildfile must contain either a PBXFileReference directly
+ referencing that path, or it must contain a PBXVariantGroup that itself
+ contains a PBXFileReference referencing the path.
+
+ If path is not specified, either the PBXFileReference's path or the paths
+ of all children of the PBXVariantGroup are taken as being added to the
+ phase.
+
+ If the path is already present in the phase, raises an exception.
+
+ If the PBXFileReference or PBXVariantGroup referenced by pbxbuildfile
+ are already present in the phase, referenced by a different PBXBuildFile
+ object, raises an exception. This does not raise an exception when
+ a PBXFileReference or PBXVariantGroup reappear and are referenced by the
+ same PBXBuildFile that has already introduced them, because in the case
+ of PBXVariantGroup objects, they may correspond to multiple paths that are
+ not all added simultaneously. When this situation occurs, the path needs
+ to be added to _files_by_path, but nothing needs to change in
+ _files_by_xcfilelikeelement, and the caller should have avoided adding
+ the PBXBuildFile if it is already present in the list of children.
+ """
+
+ xcfilelikeelement = pbxbuildfile._properties['fileRef']
+
+ paths = []
+ if path != None:
+ # It's best when the caller provides the path.
+ if isinstance(xcfilelikeelement, PBXVariantGroup):
+ paths.append(path)
+ else:
+ # If the caller didn't provide a path, there can be either multiple
+ # paths (PBXVariantGroup) or one.
+ if isinstance(xcfilelikeelement, PBXVariantGroup):
+ for variant in xcfilelikeelement._properties['children']:
+ paths.append(variant.FullPath())
+ else:
+ paths.append(xcfilelikeelement.FullPath())
+
+ # Add the paths first, because if something's going to raise, the
+ # messages provided by _AddPathToDict are more useful owing to its
+ # having access to a real pathname and not just an object's Name().
+ for a_path in paths:
+ self._AddPathToDict(pbxbuildfile, a_path)
+
+ # If another PBXBuildFile references this XCFileLikeElement, there's a
+ # problem.
+ if xcfilelikeelement in self._files_by_xcfilelikeelement and \
+ self._files_by_xcfilelikeelement[xcfilelikeelement] != pbxbuildfile:
+ raise ValueError, 'Found multiple build files for ' + \
+ xcfilelikeelement.Name()
+ self._files_by_xcfilelikeelement[xcfilelikeelement] = pbxbuildfile
+
+ def AppendBuildFile(self, pbxbuildfile, path=None):
+ # Callers should use this instead of calling
+ # AppendProperty('files', pbxbuildfile) directly because this function
+ # maintains the object's dicts. Better yet, callers can just call AddFile
+ # with a pathname and not worry about building their own PBXBuildFile
+ # objects.
+ self.AppendProperty('files', pbxbuildfile)
+ self._AddBuildFileToDicts(pbxbuildfile, path)
+
+ def AddFile(self, path, settings=None):
+ (file_group, hierarchical) = self.FileGroup(path)
+ file_ref = file_group.AddOrGetFileByPath(path, hierarchical)
+
+ if file_ref in self._files_by_xcfilelikeelement and \
+ isinstance(file_ref, PBXVariantGroup):
+ # There's already a PBXBuildFile in this phase corresponding to the
+ # PBXVariantGroup. path just provides a new variant that belongs to
+ # the group. Add the path to the dict.
+ pbxbuildfile = self._files_by_xcfilelikeelement[file_ref]
+ self._AddBuildFileToDicts(pbxbuildfile, path)
+ else:
+ # Add a new PBXBuildFile to get file_ref into the phase.
+ if settings is None:
+ pbxbuildfile = PBXBuildFile({'fileRef': file_ref})
+ else:
+ pbxbuildfile = PBXBuildFile({'fileRef': file_ref, 'settings': settings})
+ self.AppendBuildFile(pbxbuildfile, path)
+
+
+class PBXHeadersBuildPhase(XCBuildPhase):
+ # No additions to the schema relative to XCBuildPhase.
+
+ def Name(self):
+ return 'Headers'
+
+ def FileGroup(self, path):
+ return self.PBXProjectAncestor().RootGroupForPath(path)
+
+
+class PBXResourcesBuildPhase(XCBuildPhase):
+ # No additions to the schema relative to XCBuildPhase.
+
+ def Name(self):
+ return 'Resources'
+
+ def FileGroup(self, path):
+ return self.PBXProjectAncestor().RootGroupForPath(path)
+
+
+class PBXSourcesBuildPhase(XCBuildPhase):
+ # No additions to the schema relative to XCBuildPhase.
+
+ def Name(self):
+ return 'Sources'
+
+ def FileGroup(self, path):
+ return self.PBXProjectAncestor().RootGroupForPath(path)
+
+
+class PBXFrameworksBuildPhase(XCBuildPhase):
+ # No additions to the schema relative to XCBuildPhase.
+
+ def Name(self):
+ return 'Frameworks'
+
+ def FileGroup(self, path):
+ (root, ext) = posixpath.splitext(path)
+ if ext != '':
+ ext = ext[1:].lower()
+ if ext == 'o':
+ # .o files are added to Xcode Frameworks phases, but conceptually aren't
+ # frameworks, they're more like sources or intermediates. Redirect them
+ # to show up in one of those other groups.
+ return self.PBXProjectAncestor().RootGroupForPath(path)
+ else:
+ return (self.PBXProjectAncestor().FrameworksGroup(), False)
+
+
+class PBXShellScriptBuildPhase(XCBuildPhase):
+ _schema = XCBuildPhase._schema.copy()
+ _schema.update({
+ 'inputPaths': [1, str, 0, 1, []],
+ 'name': [0, str, 0, 0],
+ 'outputPaths': [1, str, 0, 1, []],
+ 'shellPath': [0, str, 0, 1, '/bin/sh'],
+ 'shellScript': [0, str, 0, 1],
+ 'showEnvVarsInLog': [0, int, 0, 0],
+ })
+
+ def Name(self):
+ if 'name' in self._properties:
+ return self._properties['name']
+
+ return 'ShellScript'
+
+
+class PBXCopyFilesBuildPhase(XCBuildPhase):
+ _schema = XCBuildPhase._schema.copy()
+ _schema.update({
+ 'dstPath': [0, str, 0, 1],
+ 'dstSubfolderSpec': [0, int, 0, 1],
+ 'name': [0, str, 0, 0],
+ })
+
+ # path_tree_re matches "$(DIR)/path" or just "$(DIR)". Match group 1 is
+ # "DIR", match group 3 is "path" or None.
+ path_tree_re = re.compile('^\\$\\((.*)\\)(/(.*)|)$')
+
+ # path_tree_to_subfolder maps names of Xcode variables to the associated
+ # dstSubfolderSpec property value used in a PBXCopyFilesBuildPhase object.
+ path_tree_to_subfolder = {
+ 'BUILT_PRODUCTS_DIR': 16, # Products Directory
+ # Other types that can be chosen via the Xcode UI.
+ # TODO(mark): Map Xcode variable names to these.
+ # : 1, # Wrapper
+ # : 6, # Executables: 6
+ # : 7, # Resources
+ # : 15, # Java Resources
+ # : 10, # Frameworks
+ # : 11, # Shared Frameworks
+ # : 12, # Shared Support
+ # : 13, # PlugIns
+ }
+
+ def Name(self):
+ if 'name' in self._properties:
+ return self._properties['name']
+
+ return 'CopyFiles'
+
+ def FileGroup(self, path):
+ return self.PBXProjectAncestor().RootGroupForPath(path)
+
+ def SetDestination(self, path):
+ """Set the dstSubfolderSpec and dstPath properties from path.
+
+ path may be specified in the same notation used for XCHierarchicalElements,
+ specifically, "$(DIR)/path".
+ """
+
+ path_tree_match = self.path_tree_re.search(path)
+ if path_tree_match:
+ # Everything else needs to be relative to an Xcode variable.
+ path_tree = path_tree_match.group(1)
+ relative_path = path_tree_match.group(3)
+
+ if path_tree in self.path_tree_to_subfolder:
+ subfolder = self.path_tree_to_subfolder[path_tree]
+ if relative_path == None:
+ relative_path = ''
+ else:
+ # The path starts with an unrecognized Xcode variable
+ # name like $(SRCROOT). Xcode will still handle this
+ # as an "absolute path" that starts with the variable.
+ subfolder = 0
+ relative_path = path
+ elif path.startswith('/'):
+ # Special case. Absolute paths are in dstSubfolderSpec 0.
+ subfolder = 0
+ relative_path = path[1:]
+ else:
+ raise ValueError, 'Can\'t use path %s in a %s' % \
+ (path, self.__class__.__name__)
+
+ self._properties['dstPath'] = relative_path
+ self._properties['dstSubfolderSpec'] = subfolder
+
+
+class PBXBuildRule(XCObject):
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'compilerSpec': [0, str, 0, 1],
+ 'filePatterns': [0, str, 0, 0],
+ 'fileType': [0, str, 0, 1],
+ 'isEditable': [0, int, 0, 1, 1],
+ 'outputFiles': [1, str, 0, 1, []],
+ 'script': [0, str, 0, 0],
+ })
+
+ def Name(self):
+ # Not very inspired, but it's what Xcode uses.
+ return self.__class__.__name__
+
+ def Hashables(self):
+ # super
+ hashables = XCObject.Hashables(self)
+
+ # Use the hashables of the weak objects that this object refers to.
+ hashables.append(self._properties['fileType'])
+ if 'filePatterns' in self._properties:
+ hashables.append(self._properties['filePatterns'])
+ return hashables
+
+
+class PBXContainerItemProxy(XCObject):
+ # When referencing an item in this project file, containerPortal is the
+ # PBXProject root object of this project file. When referencing an item in
+ # another project file, containerPortal is a PBXFileReference identifying
+ # the other project file.
+ #
+ # When serving as a proxy to an XCTarget (in this project file or another),
+ # proxyType is 1. When serving as a proxy to a PBXFileReference (in another
+ # project file), proxyType is 2. Type 2 is used for references to the
+ # producs of the other project file's targets.
+ #
+ # Xcode is weird about remoteGlobalIDString. Usually, it's printed without
+ # a comment, indicating that it's tracked internally simply as a string, but
+ # sometimes it's printed with a comment (usually when the object is initially
+ # created), indicating that it's tracked as a project file object at least
+ # sometimes. This module always tracks it as an object, but contains a hack
+ # to prevent it from printing the comment in the project file output. See
+ # _XCKVPrint.
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'containerPortal': [0, XCContainerPortal, 0, 1],
+ 'proxyType': [0, int, 0, 1],
+ 'remoteGlobalIDString': [0, XCRemoteObject, 0, 1],
+ 'remoteInfo': [0, str, 0, 1],
+ })
+
+ def __repr__(self):
+ props = self._properties
+ name = '%s.gyp:%s' % (props['containerPortal'].Name(), props['remoteInfo'])
+ return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+
+ def Name(self):
+ # Admittedly not the best name, but it's what Xcode uses.
+ return self.__class__.__name__
+
+ def Hashables(self):
+ # super
+ hashables = XCObject.Hashables(self)
+
+ # Use the hashables of the weak objects that this object refers to.
+ hashables.extend(self._properties['containerPortal'].Hashables())
+ hashables.extend(self._properties['remoteGlobalIDString'].Hashables())
+ return hashables
+
+
+class PBXTargetDependency(XCObject):
+ # The "target" property accepts an XCTarget object, and obviously not
+ # NoneType. But XCTarget is defined below, so it can't be put into the
+ # schema yet. The definition of PBXTargetDependency can't be moved below
+ # XCTarget because XCTarget's own schema references PBXTargetDependency.
+ # Python doesn't deal well with this circular relationship, and doesn't have
+ # a real way to do forward declarations. To work around, the type of
+ # the "target" property is reset below, after XCTarget is defined.
+ #
+ # At least one of "name" and "target" is required.
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'name': [0, str, 0, 0],
+ 'target': [0, None.__class__, 0, 0],
+ 'targetProxy': [0, PBXContainerItemProxy, 1, 1],
+ })
+
+ def __repr__(self):
+ name = self._properties.get('name') or self._properties['target'].Name()
+ return '<%s %r at 0x%x>' % (self.__class__.__name__, name, id(self))
+
+ def Name(self):
+ # Admittedly not the best name, but it's what Xcode uses.
+ return self.__class__.__name__
+
+ def Hashables(self):
+ # super
+ hashables = XCObject.Hashables(self)
+
+ # Use the hashables of the weak objects that this object refers to.
+ hashables.extend(self._properties['targetProxy'].Hashables())
+ return hashables
+
+
+class PBXReferenceProxy(XCFileLikeElement):
+ _schema = XCFileLikeElement._schema.copy()
+ _schema.update({
+ 'fileType': [0, str, 0, 1],
+ 'path': [0, str, 0, 1],
+ 'remoteRef': [0, PBXContainerItemProxy, 1, 1],
+ })
+
+
+class XCTarget(XCRemoteObject):
+ # An XCTarget is really just an XCObject, the XCRemoteObject thing is just
+ # to allow PBXProject to be used in the remoteGlobalIDString property of
+ # PBXContainerItemProxy.
+ #
+ # Setting a "name" property at instantiation may also affect "productName",
+ # which may in turn affect the "PRODUCT_NAME" build setting in children of
+ # "buildConfigurationList". See __init__ below.
+ _schema = XCRemoteObject._schema.copy()
+ _schema.update({
+ 'buildConfigurationList': [0, XCConfigurationList, 1, 1,
+ XCConfigurationList()],
+ 'buildPhases': [1, XCBuildPhase, 1, 1, []],
+ 'dependencies': [1, PBXTargetDependency, 1, 1, []],
+ 'name': [0, str, 0, 1],
+ 'productName': [0, str, 0, 1],
+ })
+
+ def __init__(self, properties=None, id=None, parent=None,
+ force_outdir=None, force_prefix=None, force_extension=None):
+ # super
+ XCRemoteObject.__init__(self, properties, id, parent)
+
+ # Set up additional defaults not expressed in the schema. If a "name"
+ # property was supplied, set "productName" if it is not present. Also set
+ # the "PRODUCT_NAME" build setting in each configuration, but only if
+ # the setting is not present in any build configuration.
+ if 'name' in self._properties:
+ if not 'productName' in self._properties:
+ self.SetProperty('productName', self._properties['name'])
+
+ if 'productName' in self._properties:
+ if 'buildConfigurationList' in self._properties:
+ configs = self._properties['buildConfigurationList']
+ if configs.HasBuildSetting('PRODUCT_NAME') == 0:
+ configs.SetBuildSetting('PRODUCT_NAME',
+ self._properties['productName'])
+
+ def AddDependency(self, other):
+ pbxproject = self.PBXProjectAncestor()
+ other_pbxproject = other.PBXProjectAncestor()
+ if pbxproject == other_pbxproject:
+ # The easy case. Add a dependency to another target in the same
+ # project file.
+ container = PBXContainerItemProxy({'containerPortal': pbxproject,
+ 'proxyType': 1,
+ 'remoteGlobalIDString': other,
+ 'remoteInfo': other.Name()})
+ dependency = PBXTargetDependency({'target': other,
+ 'targetProxy': container})
+ self.AppendProperty('dependencies', dependency)
+ else:
+ # The hard case. Add a dependency to a target in a different project
+ # file. Actually, this case isn't really so hard.
+ other_project_ref = \
+ pbxproject.AddOrGetProjectReference(other_pbxproject)[1]
+ container = PBXContainerItemProxy({
+ 'containerPortal': other_project_ref,
+ 'proxyType': 1,
+ 'remoteGlobalIDString': other,
+ 'remoteInfo': other.Name(),
+ })
+ dependency = PBXTargetDependency({'name': other.Name(),
+ 'targetProxy': container})
+ self.AppendProperty('dependencies', dependency)
+
+ # Proxy all of these through to the build configuration list.
+
+ def ConfigurationNamed(self, name):
+ return self._properties['buildConfigurationList'].ConfigurationNamed(name)
+
+ def DefaultConfiguration(self):
+ return self._properties['buildConfigurationList'].DefaultConfiguration()
+
+ def HasBuildSetting(self, key):
+ return self._properties['buildConfigurationList'].HasBuildSetting(key)
+
+ def GetBuildSetting(self, key):
+ return self._properties['buildConfigurationList'].GetBuildSetting(key)
+
+ def SetBuildSetting(self, key, value):
+ return self._properties['buildConfigurationList'].SetBuildSetting(key, \
+ value)
+
+ def AppendBuildSetting(self, key, value):
+ return self._properties['buildConfigurationList'].AppendBuildSetting(key, \
+ value)
+
+ def DelBuildSetting(self, key):
+ return self._properties['buildConfigurationList'].DelBuildSetting(key)
+
+
+# Redefine the type of the "target" property. See PBXTargetDependency._schema
+# above.
+PBXTargetDependency._schema['target'][1] = XCTarget
+
+
+class PBXNativeTarget(XCTarget):
+ # buildPhases is overridden in the schema to be able to set defaults.
+ #
+ # NOTE: Contrary to most objects, it is advisable to set parent when
+ # constructing PBXNativeTarget. A parent of an XCTarget must be a PBXProject
+ # object. A parent reference is required for a PBXNativeTarget during
+ # construction to be able to set up the target defaults for productReference,
+ # because a PBXBuildFile object must be created for the target and it must
+ # be added to the PBXProject's mainGroup hierarchy.
+ _schema = XCTarget._schema.copy()
+ _schema.update({
+ 'buildPhases': [1, XCBuildPhase, 1, 1,
+ [PBXSourcesBuildPhase(), PBXFrameworksBuildPhase()]],
+ 'buildRules': [1, PBXBuildRule, 1, 1, []],
+ 'productReference': [0, PBXFileReference, 0, 1],
+ 'productType': [0, str, 0, 1],
+ })
+
+ # Mapping from Xcode product-types to settings. The settings are:
+ # filetype : used for explicitFileType in the project file
+ # prefix : the prefix for the file name
+ # suffix : the suffix for the filen ame
+ _product_filetypes = {
+ 'com.apple.product-type.application': ['wrapper.application',
+ '', '.app'],
+ 'com.apple.product-type.bundle': ['wrapper.cfbundle',
+ '', '.bundle'],
+ 'com.apple.product-type.framework': ['wrapper.framework',
+ '', '.framework'],
+ 'com.apple.product-type.library.dynamic': ['compiled.mach-o.dylib',
+ 'lib', '.dylib'],
+ 'com.apple.product-type.library.static': ['archive.ar',
+ 'lib', '.a'],
+ 'com.apple.product-type.tool': ['compiled.mach-o.executable',
+ '', ''],
+ 'com.googlecode.gyp.xcode.bundle': ['compiled.mach-o.dylib',
+ '', '.so'],
+ }
+
+ def __init__(self, properties=None, id=None, parent=None,
+ force_outdir=None, force_prefix=None, force_extension=None):
+ # super
+ XCTarget.__init__(self, properties, id, parent)
+
+ if 'productName' in self._properties and \
+ 'productType' in self._properties and \
+ not 'productReference' in self._properties and \
+ self._properties['productType'] in self._product_filetypes:
+ products_group = None
+ pbxproject = self.PBXProjectAncestor()
+ if pbxproject != None:
+ products_group = pbxproject.ProductsGroup()
+
+ if products_group != None:
+ (filetype, prefix, suffix) = \
+ self._product_filetypes[self._properties['productType']]
+ # Xcode does not have a distinct type for loadable modules that are
+ # pure BSD targets (not in a bundle wrapper). GYP allows such modules
+ # to be specified by setting a target type to loadable_module without
+ # having mac_bundle set. These are mapped to the pseudo-product type
+ # com.googlecode.gyp.xcode.bundle.
+ #
+ # By picking up this special type and converting it to a dynamic
+ # library (com.apple.product-type.library.dynamic) with fix-ups,
+ # single-file loadable modules can be produced.
+ #
+ # MACH_O_TYPE is changed to mh_bundle to produce the proper file type
+ # (as opposed to mh_dylib). In order for linking to succeed,
+ # DYLIB_CURRENT_VERSION and DYLIB_COMPATIBILITY_VERSION must be
+ # cleared. They are meaningless for type mh_bundle.
+ #
+ # Finally, the .so extension is forcibly applied over the default
+ # (.dylib), unless another forced extension is already selected.
+ # .dylib is plainly wrong, and .bundle is used by loadable_modules in
+ # bundle wrappers (com.apple.product-type.bundle). .so seems an odd
+ # choice because it's used as the extension on many other systems that
+ # don't distinguish between linkable shared libraries and non-linkable
+ # loadable modules, but there's precedent: Python loadable modules on
+ # Mac OS X use an .so extension.
+ if self._properties['productType'] == 'com.googlecode.gyp.xcode.bundle':
+ self._properties['productType'] = \
+ 'com.apple.product-type.library.dynamic'
+ self.SetBuildSetting('MACH_O_TYPE', 'mh_bundle')
+ self.SetBuildSetting('DYLIB_CURRENT_VERSION', '')
+ self.SetBuildSetting('DYLIB_COMPATIBILITY_VERSION', '')
+ if force_extension == None:
+ force_extension = suffix[1:]
+
+ if force_extension is not None:
+ # If it's a wrapper (bundle), set WRAPPER_EXTENSION.
+ if filetype.startswith('wrapper.'):
+ self.SetBuildSetting('WRAPPER_EXTENSION', force_extension)
+ else:
+ # Extension override.
+ suffix = '.' + force_extension
+ self.SetBuildSetting('EXECUTABLE_EXTENSION', force_extension)
+
+ if filetype.startswith('compiled.mach-o.executable'):
+ product_name = self._properties['productName']
+ product_name += suffix
+ suffix = ''
+ self.SetProperty('productName', product_name)
+ self.SetBuildSetting('PRODUCT_NAME', product_name)
+
+ # Xcode handles most prefixes based on the target type, however there
+ # are exceptions. If a "BSD Dynamic Library" target is added in the
+ # Xcode UI, Xcode sets EXECUTABLE_PREFIX. This check duplicates that
+ # behavior.
+ if force_prefix is not None:
+ prefix = force_prefix
+ if filetype.startswith('wrapper.'):
+ self.SetBuildSetting('WRAPPER_PREFIX', prefix)
+ else:
+ self.SetBuildSetting('EXECUTABLE_PREFIX', prefix)
+
+ if force_outdir is not None:
+ self.SetBuildSetting('TARGET_BUILD_DIR', force_outdir)
+
+ # TODO(tvl): Remove the below hack.
+ # http://code.google.com/p/gyp/issues/detail?id=122
+
+ # Some targets include the prefix in the target_name. These targets
+ # really should just add a product_name setting that doesn't include
+ # the prefix. For example:
+ # target_name = 'libevent', product_name = 'event'
+ # This check cleans up for them.
+ product_name = self._properties['productName']
+ prefix_len = len(prefix)
+ if prefix_len and (product_name[:prefix_len] == prefix):
+ product_name = product_name[prefix_len:]
+ self.SetProperty('productName', product_name)
+ self.SetBuildSetting('PRODUCT_NAME', product_name)
+
+ ref_props = {
+ 'explicitFileType': filetype,
+ 'includeInIndex': 0,
+ 'path': prefix + product_name + suffix,
+ 'sourceTree': 'BUILT_PRODUCTS_DIR',
+ }
+ file_ref = PBXFileReference(ref_props)
+ products_group.AppendChild(file_ref)
+ self.SetProperty('productReference', file_ref)
+
+ def GetBuildPhaseByType(self, type):
+ if not 'buildPhases' in self._properties:
+ return None
+
+ the_phase = None
+ for phase in self._properties['buildPhases']:
+ if isinstance(phase, type):
+ # Some phases may be present in multiples in a well-formed project file,
+ # but phases like PBXSourcesBuildPhase may only be present singly, and
+ # this function is intended as an aid to GetBuildPhaseByType. Loop
+ # over the entire list of phases and assert if more than one of the
+ # desired type is found.
+ assert the_phase == None
+ the_phase = phase
+
+ return the_phase
+
+ def HeadersPhase(self):
+ headers_phase = self.GetBuildPhaseByType(PBXHeadersBuildPhase)
+ if headers_phase == None:
+ headers_phase = PBXHeadersBuildPhase()
+
+ # The headers phase should come before the resources, sources, and
+ # frameworks phases, if any.
+ insert_at = len(self._properties['buildPhases'])
+ for index in xrange(0, len(self._properties['buildPhases'])):
+ phase = self._properties['buildPhases'][index]
+ if isinstance(phase, PBXResourcesBuildPhase) or \
+ isinstance(phase, PBXSourcesBuildPhase) or \
+ isinstance(phase, PBXFrameworksBuildPhase):
+ insert_at = index
+ break
+
+ self._properties['buildPhases'].insert(insert_at, headers_phase)
+ headers_phase.parent = self
+
+ return headers_phase
+
+ def ResourcesPhase(self):
+ resources_phase = self.GetBuildPhaseByType(PBXResourcesBuildPhase)
+ if resources_phase == None:
+ resources_phase = PBXResourcesBuildPhase()
+
+ # The resources phase should come before the sources and frameworks
+ # phases, if any.
+ insert_at = len(self._properties['buildPhases'])
+ for index in xrange(0, len(self._properties['buildPhases'])):
+ phase = self._properties['buildPhases'][index]
+ if isinstance(phase, PBXSourcesBuildPhase) or \
+ isinstance(phase, PBXFrameworksBuildPhase):
+ insert_at = index
+ break
+
+ self._properties['buildPhases'].insert(insert_at, resources_phase)
+ resources_phase.parent = self
+
+ return resources_phase
+
+ def SourcesPhase(self):
+ sources_phase = self.GetBuildPhaseByType(PBXSourcesBuildPhase)
+ if sources_phase == None:
+ sources_phase = PBXSourcesBuildPhase()
+ self.AppendProperty('buildPhases', sources_phase)
+
+ return sources_phase
+
+ def FrameworksPhase(self):
+ frameworks_phase = self.GetBuildPhaseByType(PBXFrameworksBuildPhase)
+ if frameworks_phase == None:
+ frameworks_phase = PBXFrameworksBuildPhase()
+ self.AppendProperty('buildPhases', frameworks_phase)
+
+ return frameworks_phase
+
+ def AddDependency(self, other):
+ # super
+ XCTarget.AddDependency(self, other)
+
+ static_library_type = 'com.apple.product-type.library.static'
+ shared_library_type = 'com.apple.product-type.library.dynamic'
+ framework_type = 'com.apple.product-type.framework'
+ if isinstance(other, PBXNativeTarget) and \
+ 'productType' in self._properties and \
+ self._properties['productType'] != static_library_type and \
+ 'productType' in other._properties and \
+ (other._properties['productType'] == static_library_type or \
+ ((other._properties['productType'] == shared_library_type or \
+ other._properties['productType'] == framework_type) and \
+ ((not other.HasBuildSetting('MACH_O_TYPE')) or
+ other.GetBuildSetting('MACH_O_TYPE') != 'mh_bundle'))):
+
+ file_ref = other.GetProperty('productReference')
+
+ pbxproject = self.PBXProjectAncestor()
+ other_pbxproject = other.PBXProjectAncestor()
+ if pbxproject != other_pbxproject:
+ other_project_product_group = \
+ pbxproject.AddOrGetProjectReference(other_pbxproject)[0]
+ file_ref = other_project_product_group.GetChildByRemoteObject(file_ref)
+
+ self.FrameworksPhase().AppendProperty('files',
+ PBXBuildFile({'fileRef': file_ref}))
+
+
+class PBXAggregateTarget(XCTarget):
+ pass
+
+
+class PBXProject(XCContainerPortal):
+ # A PBXProject is really just an XCObject, the XCContainerPortal thing is
+ # just to allow PBXProject to be used in the containerPortal property of
+ # PBXContainerItemProxy.
+ """
+
+ Attributes:
+ path: "sample.xcodeproj". TODO(mark) Document me!
+ _other_pbxprojects: A dictionary, keyed by other PBXProject objects. Each
+ value is a reference to the dict in the
+ projectReferences list associated with the keyed
+ PBXProject.
+ """
+
+ _schema = XCContainerPortal._schema.copy()
+ _schema.update({
+ 'attributes': [0, dict, 0, 0],
+ 'buildConfigurationList': [0, XCConfigurationList, 1, 1,
+ XCConfigurationList()],
+ 'compatibilityVersion': [0, str, 0, 1, 'Xcode 3.1'],
+ 'hasScannedForEncodings': [0, int, 0, 1, 1],
+ 'mainGroup': [0, PBXGroup, 1, 1, PBXGroup()],
+ 'projectDirPath': [0, str, 0, 1, ''],
+ 'projectReferences': [1, dict, 0, 0],
+ 'projectRoot': [0, str, 0, 1, ''],
+ 'targets': [1, XCTarget, 1, 1, []],
+ })
+
+ def __init__(self, properties=None, id=None, parent=None, path=None):
+ self.path = path
+ self._other_pbxprojects = {}
+ # super
+ return XCContainerPortal.__init__(self, properties, id, parent)
+
+ def Name(self):
+ name = self.path
+ if name[-10:] == '.xcodeproj':
+ name = name[:-10]
+ return posixpath.basename(name)
+
+ def Path(self):
+ return self.path
+
+ def Comment(self):
+ return 'Project object'
+
+ def Children(self):
+ # super
+ children = XCContainerPortal.Children(self)
+
+ # Add children that the schema doesn't know about. Maybe there's a more
+ # elegant way around this, but this is the only case where we need to own
+ # objects in a dictionary (that is itself in a list), and three lines for
+ # a one-off isn't that big a deal.
+ if 'projectReferences' in self._properties:
+ for reference in self._properties['projectReferences']:
+ children.append(reference['ProductGroup'])
+
+ return children
+
+ def PBXProjectAncestor(self):
+ return self
+
+ def _GroupByName(self, name):
+ if not 'mainGroup' in self._properties:
+ self.SetProperty('mainGroup', PBXGroup())
+
+ main_group = self._properties['mainGroup']
+ group = main_group.GetChildByName(name)
+ if group == None:
+ group = PBXGroup({'name': name})
+ main_group.AppendChild(group)
+
+ return group
+
+ # SourceGroup and ProductsGroup are created by default in Xcode's own
+ # templates.
+ def SourceGroup(self):
+ return self._GroupByName('Source')
+
+ def ProductsGroup(self):
+ return self._GroupByName('Products')
+
+ # IntermediatesGroup is used to collect source-like files that are generated
+ # by rules or script phases and are placed in intermediate directories such
+ # as DerivedSources.
+ def IntermediatesGroup(self):
+ return self._GroupByName('Intermediates')
+
+ # FrameworksGroup and ProjectsGroup are top-level groups used to collect
+ # frameworks and projects.
+ def FrameworksGroup(self):
+ return self._GroupByName('Frameworks')
+
+ def ProjectsGroup(self):
+ return self._GroupByName('Projects')
+
+ def RootGroupForPath(self, path):
+ """Returns a PBXGroup child of this object to which path should be added.
+
+ This method is intended to choose between SourceGroup and
+ IntermediatesGroup on the basis of whether path is present in a source
+ directory or an intermediates directory. For the purposes of this
+ determination, any path located within a derived file directory such as
+ PROJECT_DERIVED_FILE_DIR is treated as being in an intermediates
+ directory.
+
+ The returned value is a two-element tuple. The first element is the
+ PBXGroup, and the second element specifies whether that group should be
+ organized hierarchically (True) or as a single flat list (False).
+ """
+
+ # TODO(mark): make this a class variable and bind to self on call?
+ # Also, this list is nowhere near exhaustive.
+ # INTERMEDIATE_DIR and SHARED_INTERMEDIATE_DIR are used by
+ # gyp.generator.xcode. There should probably be some way for that module
+ # to push the names in, rather than having to hard-code them here.
+ source_tree_groups = {
+ 'DERIVED_FILE_DIR': (self.IntermediatesGroup, True),
+ 'INTERMEDIATE_DIR': (self.IntermediatesGroup, True),
+ 'PROJECT_DERIVED_FILE_DIR': (self.IntermediatesGroup, True),
+ 'SHARED_INTERMEDIATE_DIR': (self.IntermediatesGroup, True),
+ }
+
+ (source_tree, path) = SourceTreeAndPathFromPath(path)
+ if source_tree != None and source_tree in source_tree_groups:
+ (group_func, hierarchical) = source_tree_groups[source_tree]
+ group = group_func()
+ return (group, hierarchical)
+
+ # TODO(mark): make additional choices based on file extension.
+
+ return (self.SourceGroup(), True)
+
+ def AddOrGetFileInRootGroup(self, path):
+ """Returns a PBXFileReference corresponding to path in the correct group
+ according to RootGroupForPath's heuristics.
+
+ If an existing PBXFileReference for path exists, it will be returned.
+ Otherwise, one will be created and returned.
+ """
+
+ (group, hierarchical) = self.RootGroupForPath(path)
+ return group.AddOrGetFileByPath(path, hierarchical)
+
+ def RootGroupsTakeOverOnlyChildren(self, recurse=False):
+ """Calls TakeOverOnlyChild for all groups in the main group."""
+
+ for group in self._properties['mainGroup']._properties['children']:
+ if isinstance(group, PBXGroup):
+ group.TakeOverOnlyChild(recurse)
+
+ def SortGroups(self):
+ # Sort the children of the mainGroup (like "Source" and "Products")
+ # according to their defined order.
+ self._properties['mainGroup']._properties['children'] = \
+ sorted(self._properties['mainGroup']._properties['children'],
+ cmp=lambda x,y: x.CompareRootGroup(y))
+
+ # Sort everything else by putting group before files, and going
+ # alphabetically by name within sections of groups and files. SortGroup
+ # is recursive.
+ for group in self._properties['mainGroup']._properties['children']:
+ if not isinstance(group, PBXGroup):
+ continue
+
+ if group.Name() == 'Products':
+ # The Products group is a special case. Instead of sorting
+ # alphabetically, sort things in the order of the targets that
+ # produce the products. To do this, just build up a new list of
+ # products based on the targets.
+ products = []
+ for target in self._properties['targets']:
+ if not isinstance(target, PBXNativeTarget):
+ continue
+ product = target._properties['productReference']
+ # Make sure that the product is already in the products group.
+ assert product in group._properties['children']
+ products.append(product)
+
+ # Make sure that this process doesn't miss anything that was already
+ # in the products group.
+ assert len(products) == len(group._properties['children'])
+ group._properties['children'] = products
+ else:
+ group.SortGroup()
+
+ def AddOrGetProjectReference(self, other_pbxproject):
+ """Add a reference to another project file (via PBXProject object) to this
+ one.
+
+ Returns [ProductGroup, ProjectRef]. ProductGroup is a PBXGroup object in
+ this project file that contains a PBXReferenceProxy object for each
+ product of each PBXNativeTarget in the other project file. ProjectRef is
+ a PBXFileReference to the other project file.
+
+ If this project file already references the other project file, the
+ existing ProductGroup and ProjectRef are returned. The ProductGroup will
+ still be updated if necessary.
+ """
+
+ if not 'projectReferences' in self._properties:
+ self._properties['projectReferences'] = []
+
+ product_group = None
+ project_ref = None
+
+ if not other_pbxproject in self._other_pbxprojects:
+ # This project file isn't yet linked to the other one. Establish the
+ # link.
+ product_group = PBXGroup({'name': 'Products'})
+
+ # ProductGroup is strong.
+ product_group.parent = self
+
+ # There's nothing unique about this PBXGroup, and if left alone, it will
+ # wind up with the same set of hashables as all other PBXGroup objects
+ # owned by the projectReferences list. Add the hashables of the
+ # remote PBXProject that it's related to.
+ product_group._hashables.extend(other_pbxproject.Hashables())
+
+ # The other project reports its path as relative to the same directory
+ # that this project's path is relative to. The other project's path
+ # is not necessarily already relative to this project. Figure out the
+ # pathname that this project needs to use to refer to the other one.
+ this_path = posixpath.dirname(self.Path())
+ projectDirPath = self.GetProperty('projectDirPath')
+ if projectDirPath:
+ if posixpath.isabs(projectDirPath[0]):
+ this_path = projectDirPath
+ else:
+ this_path = posixpath.join(this_path, projectDirPath)
+ other_path = gyp.common.RelativePath(other_pbxproject.Path(), this_path)
+
+ # ProjectRef is weak (it's owned by the mainGroup hierarchy).
+ project_ref = PBXFileReference({
+ 'lastKnownFileType': 'wrapper.pb-project',
+ 'path': other_path,
+ 'sourceTree': 'SOURCE_ROOT',
+ })
+ self.ProjectsGroup().AppendChild(project_ref)
+
+ ref_dict = {'ProductGroup': product_group, 'ProjectRef': project_ref}
+ self._other_pbxprojects[other_pbxproject] = ref_dict
+ self.AppendProperty('projectReferences', ref_dict)
+
+ # Xcode seems to sort this list case-insensitively
+ self._properties['projectReferences'] = \
+ sorted(self._properties['projectReferences'], cmp=lambda x,y:
+ cmp(x['ProjectRef'].Name().lower(),
+ y['ProjectRef'].Name().lower()))
+ else:
+ # The link already exists. Pull out the relevnt data.
+ project_ref_dict = self._other_pbxprojects[other_pbxproject]
+ product_group = project_ref_dict['ProductGroup']
+ project_ref = project_ref_dict['ProjectRef']
+
+ self._SetUpProductReferences(other_pbxproject, product_group, project_ref)
+
+ return [product_group, project_ref]
+
+ def _SetUpProductReferences(self, other_pbxproject, product_group,
+ project_ref):
+ # TODO(mark): This only adds references to products in other_pbxproject
+ # when they don't exist in this pbxproject. Perhaps it should also
+ # remove references from this pbxproject that are no longer present in
+ # other_pbxproject. Perhaps it should update various properties if they
+ # change.
+ for target in other_pbxproject._properties['targets']:
+ if not isinstance(target, PBXNativeTarget):
+ continue
+
+ other_fileref = target._properties['productReference']
+ if product_group.GetChildByRemoteObject(other_fileref) == None:
+ # Xcode sets remoteInfo to the name of the target and not the name
+ # of its product, despite this proxy being a reference to the product.
+ container_item = PBXContainerItemProxy({
+ 'containerPortal': project_ref,
+ 'proxyType': 2,
+ 'remoteGlobalIDString': other_fileref,
+ 'remoteInfo': target.Name()
+ })
+ # TODO(mark): Does sourceTree get copied straight over from the other
+ # project? Can the other project ever have lastKnownFileType here
+ # instead of explicitFileType? (Use it if so?) Can path ever be
+ # unset? (I don't think so.) Can other_fileref have name set, and
+ # does it impact the PBXReferenceProxy if so? These are the questions
+ # that perhaps will be answered one day.
+ reference_proxy = PBXReferenceProxy({
+ 'fileType': other_fileref._properties['explicitFileType'],
+ 'path': other_fileref._properties['path'],
+ 'sourceTree': other_fileref._properties['sourceTree'],
+ 'remoteRef': container_item,
+ })
+
+ product_group.AppendChild(reference_proxy)
+
+ def SortRemoteProductReferences(self):
+ # For each remote project file, sort the associated ProductGroup in the
+ # same order that the targets are sorted in the remote project file. This
+ # is the sort order used by Xcode.
+
+ def CompareProducts(x, y, remote_products):
+ # x and y are PBXReferenceProxy objects. Go through their associated
+ # PBXContainerItem to get the remote PBXFileReference, which will be
+ # present in the remote_products list.
+ x_remote = x._properties['remoteRef']._properties['remoteGlobalIDString']
+ y_remote = y._properties['remoteRef']._properties['remoteGlobalIDString']
+ x_index = remote_products.index(x_remote)
+ y_index = remote_products.index(y_remote)
+
+ # Use the order of each remote PBXFileReference in remote_products to
+ # determine the sort order.
+ return cmp(x_index, y_index)
+
+ for other_pbxproject, ref_dict in self._other_pbxprojects.iteritems():
+ # Build up a list of products in the remote project file, ordered the
+ # same as the targets that produce them.
+ remote_products = []
+ for target in other_pbxproject._properties['targets']:
+ if not isinstance(target, PBXNativeTarget):
+ continue
+ remote_products.append(target._properties['productReference'])
+
+ # Sort the PBXReferenceProxy children according to the list of remote
+ # products.
+ product_group = ref_dict['ProductGroup']
+ product_group._properties['children'] = sorted(
+ product_group._properties['children'],
+ cmp=lambda x, y: CompareProducts(x, y, remote_products))
+
+
+class XCProjectFile(XCObject):
+ _schema = XCObject._schema.copy()
+ _schema.update({
+ 'archiveVersion': [0, int, 0, 1, 1],
+ 'classes': [0, dict, 0, 1, {}],
+ 'objectVersion': [0, int, 0, 1, 45],
+ 'rootObject': [0, PBXProject, 1, 1],
+ })
+
+ def SetXcodeVersion(self, version):
+ version_to_object_version = {
+ '2.4': 45,
+ '3.0': 45,
+ '3.1': 45,
+ '3.2': 46,
+ }
+ if not version in version_to_object_version:
+ supported_str = ', '.join(sorted(version_to_object_version.keys()))
+ raise Exception(
+ 'Unsupported Xcode version %s (supported: %s)' %
+ ( version, supported_str ) )
+ compatibility_version = 'Xcode %s' % version
+ self._properties['rootObject'].SetProperty('compatibilityVersion',
+ compatibility_version)
+ self.SetProperty('objectVersion', version_to_object_version[version]);
+
+ def ComputeIDs(self, recursive=True, overwrite=True, hash=None):
+ # Although XCProjectFile is implemented here as an XCObject, it's not a
+ # proper object in the Xcode sense, and it certainly doesn't have its own
+ # ID. Pass through an attempt to update IDs to the real root object.
+ if recursive:
+ self._properties['rootObject'].ComputeIDs(recursive, overwrite, hash)
+
+ def Print(self, file=sys.stdout):
+ self.VerifyHasRequiredProperties()
+
+ # Add the special "objects" property, which will be caught and handled
+ # separately during printing. This structure allows a fairly standard
+ # loop do the normal printing.
+ self._properties['objects'] = {}
+ self._XCPrint(file, 0, '// !$*UTF8*$!\n')
+ if self._should_print_single_line:
+ self._XCPrint(file, 0, '{ ')
+ else:
+ self._XCPrint(file, 0, '{\n')
+ for property, value in sorted(self._properties.iteritems(),
+ cmp=lambda x, y: cmp(x, y)):
+ if property == 'objects':
+ self._PrintObjects(file)
+ else:
+ self._XCKVPrint(file, 1, property, value)
+ self._XCPrint(file, 0, '}\n')
+ del self._properties['objects']
+
+ def _PrintObjects(self, file):
+ if self._should_print_single_line:
+ self._XCPrint(file, 0, 'objects = {')
+ else:
+ self._XCPrint(file, 1, 'objects = {\n')
+
+ objects_by_class = {}
+ for object in self.Descendants():
+ if object == self:
+ continue
+ class_name = object.__class__.__name__
+ if not class_name in objects_by_class:
+ objects_by_class[class_name] = []
+ objects_by_class[class_name].append(object)
+
+ for class_name in sorted(objects_by_class):
+ self._XCPrint(file, 0, '\n')
+ self._XCPrint(file, 0, '/* Begin ' + class_name + ' section */\n')
+ for object in sorted(objects_by_class[class_name],
+ cmp=lambda x, y: cmp(x.id, y.id)):
+ object.Print(file)
+ self._XCPrint(file, 0, '/* End ' + class_name + ' section */\n')
+
+ if self._should_print_single_line:
+ self._XCPrint(file, 0, '}; ')
+ else:
+ self._XCPrint(file, 1, '};\n')
diff --git a/Source/ThirdParty/gyp/pylib/gyp/xml_fix.py b/Source/ThirdParty/gyp/pylib/gyp/xml_fix.py
new file mode 100644
index 000000000..20f782d28
--- /dev/null
+++ b/Source/ThirdParty/gyp/pylib/gyp/xml_fix.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Applies a fix to CR LF TAB handling in xml.dom.
+
+Fixes this: http://code.google.com/p/chromium/issues/detail?id=76293
+Working around this: http://bugs.python.org/issue5752
+TODO(bradnelson): Consider dropping this when we drop XP support.
+"""
+
+
+import xml.dom.minidom
+
+
+def _Replacement_write_data(writer, data, is_attrib=False):
+ """Writes datachars to writer."""
+ data = data.replace("&", "&amp;").replace("<", "&lt;")
+ data = data.replace("\"", "&quot;").replace(">", "&gt;")
+ if is_attrib:
+ data = data.replace(
+ "\r", "&#xD;").replace(
+ "\n", "&#xA;").replace(
+ "\t", "&#x9;")
+ writer.write(data)
+
+
+def _Replacement_writexml(self, writer, indent="", addindent="", newl=""):
+ # indent = current indentation
+ # addindent = indentation to add to higher levels
+ # newl = newline string
+ writer.write(indent+"<" + self.tagName)
+
+ attrs = self._get_attributes()
+ a_names = attrs.keys()
+ a_names.sort()
+
+ for a_name in a_names:
+ writer.write(" %s=\"" % a_name)
+ _Replacement_write_data(writer, attrs[a_name].value, is_attrib=True)
+ writer.write("\"")
+ if self.childNodes:
+ writer.write(">%s" % newl)
+ for node in self.childNodes:
+ node.writexml(writer, indent + addindent, addindent, newl)
+ writer.write("%s</%s>%s" % (indent, self.tagName, newl))
+ else:
+ writer.write("/>%s" % newl)
+
+
+class XmlFix(object):
+ """Object to manage temporary patching of xml.dom.minidom."""
+
+ def __init__(self):
+ # Preserve current xml.dom.minidom functions.
+ self.write_data = xml.dom.minidom._write_data
+ self.writexml = xml.dom.minidom.Element.writexml
+ # Inject replacement versions of a function and a method.
+ xml.dom.minidom._write_data = _Replacement_write_data
+ xml.dom.minidom.Element.writexml = _Replacement_writexml
+
+ def Cleanup(self):
+ if self.write_data:
+ xml.dom.minidom._write_data = self.write_data
+ xml.dom.minidom.Element.writexml = self.writexml
+ self.write_data = None
+
+ def __del__(self):
+ self.Cleanup()
diff --git a/Source/ThirdParty/gyp/samples/samples b/Source/ThirdParty/gyp/samples/samples
new file mode 100755
index 000000000..804b61899
--- /dev/null
+++ b/Source/ThirdParty/gyp/samples/samples
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os.path
+import shutil
+import sys
+
+
+gyps = [
+ 'app/app.gyp',
+ 'base/base.gyp',
+ 'build/temp_gyp/googleurl.gyp',
+ 'build/all.gyp',
+ 'build/common.gypi',
+ 'build/external_code.gypi',
+ 'chrome/test/security_tests/security_tests.gyp',
+ 'chrome/third_party/hunspell/hunspell.gyp',
+ 'chrome/chrome.gyp',
+ 'media/media.gyp',
+ 'net/net.gyp',
+ 'printing/printing.gyp',
+ 'sdch/sdch.gyp',
+ 'skia/skia.gyp',
+ 'testing/gmock.gyp',
+ 'testing/gtest.gyp',
+ 'third_party/bzip2/bzip2.gyp',
+ 'third_party/icu38/icu38.gyp',
+ 'third_party/libevent/libevent.gyp',
+ 'third_party/libjpeg/libjpeg.gyp',
+ 'third_party/libpng/libpng.gyp',
+ 'third_party/libxml/libxml.gyp',
+ 'third_party/libxslt/libxslt.gyp',
+ 'third_party/lzma_sdk/lzma_sdk.gyp',
+ 'third_party/modp_b64/modp_b64.gyp',
+ 'third_party/npapi/npapi.gyp',
+ 'third_party/sqlite/sqlite.gyp',
+ 'third_party/zlib/zlib.gyp',
+ 'v8/tools/gyp/v8.gyp',
+ 'webkit/activex_shim/activex_shim.gyp',
+ 'webkit/activex_shim_dll/activex_shim_dll.gyp',
+ 'webkit/build/action_csspropertynames.py',
+ 'webkit/build/action_cssvaluekeywords.py',
+ 'webkit/build/action_jsconfig.py',
+ 'webkit/build/action_makenames.py',
+ 'webkit/build/action_maketokenizer.py',
+ 'webkit/build/action_useragentstylesheets.py',
+ 'webkit/build/rule_binding.py',
+ 'webkit/build/rule_bison.py',
+ 'webkit/build/rule_gperf.py',
+ 'webkit/tools/test_shell/test_shell.gyp',
+ 'webkit/webkit.gyp',
+]
+
+
+def Main(argv):
+ if len(argv) != 3 or argv[1] not in ['push', 'pull']:
+ print 'Usage: %s push/pull PATH_TO_CHROME' % argv[0]
+ return 1
+
+ path_to_chrome = argv[2]
+
+ for g in gyps:
+ chrome_file = os.path.join(path_to_chrome, g)
+ local_file = os.path.join(os.path.dirname(argv[0]), os.path.split(g)[1])
+ if argv[1] == 'push':
+ print 'Copying %s to %s' % (local_file, chrome_file)
+ shutil.copyfile(local_file, chrome_file)
+ elif argv[1] == 'pull':
+ print 'Copying %s to %s' % (chrome_file, local_file)
+ shutil.copyfile(chrome_file, local_file)
+ else:
+ assert False
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(Main(sys.argv))
diff --git a/Source/ThirdParty/gyp/samples/samples.bat b/Source/ThirdParty/gyp/samples/samples.bat
new file mode 100644
index 000000000..778d9c90f
--- /dev/null
+++ b/Source/ThirdParty/gyp/samples/samples.bat
@@ -0,0 +1,5 @@
+@rem Copyright (c) 2009 Google Inc. All rights reserved.
+@rem Use of this source code is governed by a BSD-style license that can be
+@rem found in the LICENSE file.
+
+@python %~dp0/samples %*
diff --git a/Source/ThirdParty/gyp/setup.py b/Source/ThirdParty/gyp/setup.py
new file mode 100755
index 000000000..ed2b41a3c
--- /dev/null
+++ b/Source/ThirdParty/gyp/setup.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from distutils.core import setup
+from distutils.command.install import install
+from distutils.command.install_lib import install_lib
+from distutils.command.install_scripts import install_scripts
+
+setup(
+ name='gyp',
+ version='0.1',
+ description='Generate Your Projects',
+ author='Chromium Authors',
+ author_email='chromium-dev@googlegroups.com',
+ url='http://code.google.com/p/gyp',
+ package_dir = {'': 'pylib'},
+ packages=['gyp', 'gyp.generator'],
+
+ scripts = ['gyp'],
+ cmdclass = {'install': install,
+ 'install_lib': install_lib,
+ 'install_scripts': install_scripts},
+)
diff --git a/Source/ThirdParty/gyp/test/actions-bare/gyptest-bare.py b/Source/ThirdParty/gyp/test/actions-bare/gyptest-bare.py
new file mode 100644
index 000000000..b0c10938d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-bare/gyptest-bare.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies actions which are not depended on by other targets get executed.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('bare.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('bare.gyp', chdir='relocate/src')
+
+file_content = 'Hello from bare.py\n'
+
+test.built_file_must_match('out.txt', file_content, chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/actions-bare/src/bare.gyp b/Source/ThirdParty/gyp/test/actions-bare/src/bare.gyp
new file mode 100644
index 000000000..3d28f099d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-bare/src/bare.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'bare',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'action1',
+ 'inputs': [
+ 'bare.py',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/out.txt',
+ ],
+ 'action': ['python', 'bare.py', '<(PRODUCT_DIR)/out.txt'],
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/actions-bare/src/bare.py b/Source/ThirdParty/gyp/test/actions-bare/src/bare.py
new file mode 100644
index 000000000..970450ea3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-bare/src/bare.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1], 'wb')
+f.write('Hello from bare.py\n')
+f.close()
diff --git a/Source/ThirdParty/gyp/test/actions-multiple/gyptest-all.py b/Source/ThirdParty/gyp/test/actions-multiple/gyptest-all.py
new file mode 100644
index 000000000..7b94fef40
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-multiple/gyptest-all.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies two actions can be attached to the same input files.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Test that two actions can be attached to the same inputs.
+test.build('actions.gyp', test.ALL, chdir='relocate/src')
+test.must_contain('relocate/src/output1.txt', 'hello there')
+test.must_contain('relocate/src/output2.txt', 'hello there')
+test.must_contain('relocate/src/output3.txt', 'hello there')
+test.must_contain('relocate/src/output4.txt', 'hello there')
+
+# Test that process_outputs_as_sources works in conjuction with merged
+# actions.
+test.run_built_executable(
+ 'multiple_action_source_filter',
+ chdir='relocate/src',
+ stdout=(
+ '{\n'
+ 'bar\n'
+ 'car\n'
+ 'dar\n'
+ 'ear\n'
+ '}\n'
+ ),
+)
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/actions-multiple/src/actions.gyp b/Source/ThirdParty/gyp/test/actions-multiple/src/actions.gyp
new file mode 100644
index 000000000..b38df45fd
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-multiple/src/actions.gyp
@@ -0,0 +1,165 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ # Have a long string so that actions will exceed xp 512 character
+ # command limit on xp.
+ 'long_string':
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ 'abcdefghijklmnopqrstuvwxyz0123456789'
+ },
+ 'targets': [
+ {
+ 'target_name': 'multiple_action_target',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'action1',
+ 'inputs': [
+ 'copy.py',
+ 'input.txt',
+ ],
+ 'outputs': [
+ 'output1.txt',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ {
+ 'action_name': 'action2',
+ 'inputs': [
+ 'copy.py',
+ 'input.txt',
+ ],
+ 'outputs': [
+ 'output2.txt',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ {
+ 'action_name': 'action3',
+ 'inputs': [
+ 'copy.py',
+ 'input.txt',
+ ],
+ 'outputs': [
+ 'output3.txt',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ {
+ 'action_name': 'action4',
+ 'inputs': [
+ 'copy.py',
+ 'input.txt',
+ ],
+ 'outputs': [
+ 'output4.txt',
+ ],
+ 'action': [
+ 'python', '<@(_inputs)', '<(_outputs)', '<(long_string)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ {
+ 'target_name': 'multiple_action_source_filter',
+ 'type': 'executable',
+ 'sources': [
+ 'main.c',
+ # TODO(bradnelson): add foo.c here once this issue is fixed:
+ # http://code.google.com/p/gyp/issues/detail?id=175
+ ],
+ 'actions': [
+ {
+ 'action_name': 'action1',
+ 'inputs': [
+ 'foo.c',
+ 'filter.py',
+ ],
+ 'outputs': [
+ 'output1.c',
+ ],
+ 'process_outputs_as_sources': 1,
+ 'action': [
+ 'python', 'filter.py', 'foo', 'bar', 'foo.c', '<(_outputs)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ {
+ 'action_name': 'action2',
+ 'inputs': [
+ 'foo.c',
+ 'filter.py',
+ ],
+ 'outputs': [
+ 'output2.c',
+ ],
+ 'process_outputs_as_sources': 1,
+ 'action': [
+ 'python', 'filter.py', 'foo', 'car', 'foo.c', '<(_outputs)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ {
+ 'action_name': 'action3',
+ 'inputs': [
+ 'foo.c',
+ 'filter.py',
+ ],
+ 'outputs': [
+ 'output3.c',
+ ],
+ 'process_outputs_as_sources': 1,
+ 'action': [
+ 'python', 'filter.py', 'foo', 'dar', 'foo.c', '<(_outputs)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ {
+ 'action_name': 'action4',
+ 'inputs': [
+ 'foo.c',
+ 'filter.py',
+ ],
+ 'outputs': [
+ 'output4.c',
+ ],
+ 'process_outputs_as_sources': 1,
+ 'action': [
+ 'python', 'filter.py', 'foo', 'ear', 'foo.c', '<(_outputs)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/actions-multiple/src/copy.py b/Source/ThirdParty/gyp/test/actions-multiple/src/copy.py
new file mode 100644
index 000000000..7ba29110d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-multiple/src/copy.py
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import shutil
+import sys
+
+shutil.copyfile(sys.argv[1], sys.argv[2])
diff --git a/Source/ThirdParty/gyp/test/actions-multiple/src/filter.py b/Source/ThirdParty/gyp/test/actions-multiple/src/filter.py
new file mode 100644
index 000000000..d0a0a950b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-multiple/src/filter.py
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import sys
+
+data = open(sys.argv[3], 'r').read()
+fh = open(sys.argv[4], 'w')
+fh.write(data.replace(sys.argv[1], sys.argv[2]))
+fh.close()
diff --git a/Source/ThirdParty/gyp/test/actions-multiple/src/foo.c b/Source/ThirdParty/gyp/test/actions-multiple/src/foo.c
new file mode 100644
index 000000000..23c4ef7f2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-multiple/src/foo.c
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+void foo(void) {
+ printf("foo\n");
+}
diff --git a/Source/ThirdParty/gyp/test/actions-multiple/src/input.txt b/Source/ThirdParty/gyp/test/actions-multiple/src/input.txt
new file mode 100644
index 000000000..c7c7da3c6
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-multiple/src/input.txt
@@ -0,0 +1 @@
+hello there
diff --git a/Source/ThirdParty/gyp/test/actions-multiple/src/main.c b/Source/ThirdParty/gyp/test/actions-multiple/src/main.c
new file mode 100644
index 000000000..0a420b903
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-multiple/src/main.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <stdio.h>
+
+void bar(void);
+void car(void);
+void dar(void);
+void ear(void);
+
+int main() {
+ printf("{\n");
+ bar();
+ car();
+ dar();
+ ear();
+ printf("}\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/actions-subdir/gyptest-action.py b/Source/ThirdParty/gyp/test/actions-subdir/gyptest-action.py
new file mode 100644
index 000000000..09cfef189
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-subdir/gyptest-action.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test actions that output to PRODUCT_DIR.
+"""
+
+import TestGyp
+
+# TODO fix this for xcode: http://code.google.com/p/gyp/issues/detail?id=88
+test = TestGyp.TestGyp(formats=['!xcode'])
+
+test.run_gyp('none.gyp', chdir='src')
+
+test.build('none.gyp', test.ALL, chdir='src')
+
+file_content = 'Hello from make-file.py\n'
+subdir_file_content = 'Hello from make-subdir-file.py\n'
+
+test.built_file_must_match('file.out', file_content, chdir='src')
+test.built_file_must_match('subdir_file.out', subdir_file_content, chdir='src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/actions-subdir/src/make-file.py b/Source/ThirdParty/gyp/test/actions-subdir/src/make-file.py
new file mode 100644
index 000000000..74e55811d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-subdir/src/make-file.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = 'Hello from make-file.py\n'
+
+open(sys.argv[1], 'wb').write(contents)
diff --git a/Source/ThirdParty/gyp/test/actions-subdir/src/none.gyp b/Source/ThirdParty/gyp/test/actions-subdir/src/none.gyp
new file mode 100644
index 000000000..23f8d25a5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-subdir/src/none.gyp
@@ -0,0 +1,31 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'file',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'actions': [
+ {
+ 'action_name': 'make-file',
+ 'inputs': [
+ 'make-file.py',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/file.out',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ }
+ ],
+ 'dependencies': [
+ 'subdir/subdir.gyp:subdir_file',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/actions-subdir/src/subdir/make-subdir-file.py b/Source/ThirdParty/gyp/test/actions-subdir/src/subdir/make-subdir-file.py
new file mode 100644
index 000000000..80ce19ae0
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-subdir/src/subdir/make-subdir-file.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = 'Hello from make-subdir-file.py\n'
+
+open(sys.argv[1], 'wb').write(contents)
diff --git a/Source/ThirdParty/gyp/test/actions-subdir/src/subdir/subdir.gyp b/Source/ThirdParty/gyp/test/actions-subdir/src/subdir/subdir.gyp
new file mode 100644
index 000000000..0315d4eb8
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions-subdir/src/subdir/subdir.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'subdir_file',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'actions': [
+ {
+ 'action_name': 'make-subdir-file',
+ 'inputs': [
+ 'make-subdir-file.py',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/subdir_file.out',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ }
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/actions/gyptest-all.py b/Source/ThirdParty/gyp/test/actions/gyptest-all.py
new file mode 100644
index 000000000..8db38d52c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/gyptest-all.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple actions when using an explicit build target of 'all'.
+"""
+
+import glob
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Test that an "always run" action increases a counter on multiple invocations,
+# and that a dependent action updates in step.
+test.build('actions.gyp', test.ALL, chdir='relocate/src')
+test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '1')
+test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '1')
+test.build('actions.gyp', test.ALL, chdir='relocate/src')
+test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+# The "always run" action only counts to 2, but the dependent target will count
+# forever if it's allowed to run. This verifies that the dependent target only
+# runs when the "always run" action generates new output, not just because the
+# "always run" ran.
+test.build('actions.gyp', test.ALL, chdir='relocate/src')
+test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+expect = """\
+Hello from program.c
+Hello from make-prog1.py
+Hello from make-prog2.py
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir1'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+
+test.must_match('relocate/src/subdir2/file.out', "Hello from make-file.py\n")
+
+
+expect = "Hello from generate_main.py\n"
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir3'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('null_input', chdir=chdir, stdout=expect)
+
+
+# Clean out files which may have been created if test.ALL was run.
+def clean_dep_files():
+ for file in (glob.glob('relocate/src/dep_*.txt') +
+ glob.glob('relocate/src/deps_all_done_*.txt')):
+ if os.path.exists(file):
+ os.remove(file)
+
+# Confirm our clean.
+clean_dep_files()
+test.must_not_exist('relocate/src/dep_1.txt')
+test.must_not_exist('relocate/src/deps_all_done_first_123.txt')
+
+# Make sure all deps finish before an action is run on a 'None' target.
+# If using the Make builder, add -j to make things more difficult.
+arguments = []
+if test.format == 'make':
+ arguments = ['-j']
+test.build('actions.gyp', 'action_with_dependencies_123', chdir='relocate/src',
+ arguments=arguments)
+test.must_exist('relocate/src/deps_all_done_first_123.txt')
+
+# Try again with a target that has deps in reverse. Output files from
+# previous tests deleted. Confirm this execution did NOT run the ALL
+# target which would mess up our dep tests.
+clean_dep_files()
+test.build('actions.gyp', 'action_with_dependencies_321', chdir='relocate/src',
+ arguments=arguments)
+test.must_exist('relocate/src/deps_all_done_first_321.txt')
+test.must_not_exist('relocate/src/deps_all_done_first_123.txt')
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/actions/gyptest-default.py b/Source/ThirdParty/gyp/test/actions/gyptest-default.py
new file mode 100644
index 000000000..c877867b1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/gyptest-default.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple actions when using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Test that an "always run" action increases a counter on multiple invocations,
+# and that a dependent action updates in step.
+test.build('actions.gyp', chdir='relocate/src')
+test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '1')
+test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '1')
+test.build('actions.gyp', chdir='relocate/src')
+test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+# The "always run" action only counts to 2, but the dependent target will count
+# forever if it's allowed to run. This verifies that the dependent target only
+# runs when the "always run" action generates new output, not just because the
+# "always run" ran.
+test.build('actions.gyp', test.ALL, chdir='relocate/src')
+test.must_match('relocate/src/subdir1/actions-out/action-counter.txt', '2')
+test.must_match('relocate/src/subdir1/actions-out/action-counter_2.txt', '2')
+
+expect = """\
+Hello from program.c
+Hello from make-prog1.py
+Hello from make-prog2.py
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir1'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+
+test.must_match('relocate/src/subdir2/file.out', "Hello from make-file.py\n")
+
+
+expect = "Hello from generate_main.py\n"
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir3'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('null_input', chdir=chdir, stdout=expect)
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/actions/gyptest-errors.py b/Source/ThirdParty/gyp/test/actions/gyptest-errors.py
new file mode 100644
index 000000000..ca41487bb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/gyptest-errors.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies behavior for different action configuration errors:
+exit status of 1, and the expected error message must be in stderr.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+
+test.run_gyp('action_missing_name.gyp', chdir='src', status=1, stderr=None)
+expect = [
+ "Anonymous action in target broken_actions2. An action must have an 'action_name' field.",
+]
+test.must_contain_all_lines(test.stderr(), expect)
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/actions/src/action_missing_name.gyp b/Source/ThirdParty/gyp/test/actions/src/action_missing_name.gyp
new file mode 100644
index 000000000..00424c35a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/action_missing_name.gyp
@@ -0,0 +1,24 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'broken_actions2',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'inputs': [
+ 'no_name.input',
+ ],
+ 'action': [
+ 'python',
+ '-c',
+ 'print \'missing name\'',
+ ],
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/actions/src/actions.gyp b/Source/ThirdParty/gyp/test/actions/src/actions.gyp
new file mode 100644
index 000000000..5d2db1955
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/actions.gyp
@@ -0,0 +1,114 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'pull_in_all_actions',
+ 'type': 'none',
+ 'dependencies': [
+ 'subdir1/executable.gyp:*',
+ 'subdir2/none.gyp:*',
+ 'subdir3/null_input.gyp:*',
+ ],
+ },
+ {
+ 'target_name': 'depend_on_always_run_action',
+ 'type': 'none',
+ 'dependencies': [ 'subdir1/executable.gyp:counter' ],
+ 'actions': [
+ {
+ 'action_name': 'use_always_run_output',
+ 'inputs': [
+ 'subdir1/actions-out/action-counter.txt',
+ 'subdir1/counter.py',
+ ],
+ 'outputs': [
+ 'subdir1/actions-out/action-counter_2.txt',
+ ],
+ 'action': [
+ 'python', 'subdir1/counter.py', '<(_outputs)',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+
+ # Three deps which don't finish immediately.
+ # Each one has a small delay then creates a file.
+ # Delays are 1.0, 1.1, and 2.0 seconds.
+ {
+ 'target_name': 'dep_1',
+ 'type': 'none',
+ 'actions': [{
+ 'inputs': [ 'actions.gyp' ],
+ 'outputs': [ 'dep_1.txt' ],
+ 'action_name': 'dep_1',
+ 'action': [ 'python', '-c',
+ 'import time; time.sleep(1); open(\'dep_1.txt\', \'w\')' ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ }],
+ },
+ {
+ 'target_name': 'dep_2',
+ 'type': 'none',
+ 'actions': [{
+ 'inputs': [ 'actions.gyp' ],
+ 'outputs': [ 'dep_2.txt' ],
+ 'action_name': 'dep_2',
+ 'action': [ 'python', '-c',
+ 'import time; time.sleep(1.1); open(\'dep_2.txt\', \'w\')' ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ }],
+ },
+ {
+ 'target_name': 'dep_3',
+ 'type': 'none',
+ 'actions': [{
+ 'inputs': [ 'actions.gyp' ],
+ 'outputs': [ 'dep_3.txt' ],
+ 'action_name': 'dep_3',
+ 'action': [ 'python', '-c',
+ 'import time; time.sleep(2.0); open(\'dep_3.txt\', \'w\')' ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ }],
+ },
+
+ # An action which assumes the deps have completed.
+ # Does NOT list the output files of it's deps as inputs.
+ # On success create the file deps_all_done_first.txt.
+ {
+ 'target_name': 'action_with_dependencies_123',
+ 'type': 'none',
+ 'dependencies': [ 'dep_1', 'dep_2', 'dep_3' ],
+ 'actions': [{
+ 'inputs': [ 'actions.gyp' ],
+ 'outputs': [ 'deps_all_done_first_123.txt' ],
+ 'action_name': 'action_with_dependencies_123',
+ 'action': [ 'python', 'confirm-dep-files.py', '<(_outputs)' ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ }],
+ },
+ # Same as above but with deps in reverse.
+ {
+ 'target_name': 'action_with_dependencies_321',
+ 'type': 'none',
+ 'dependencies': [ 'dep_3', 'dep_2', 'dep_1' ],
+ 'actions': [{
+ 'inputs': [ 'actions.gyp' ],
+ 'outputs': [ 'deps_all_done_first_321.txt' ],
+ 'action_name': 'action_with_dependencies_321',
+ 'action': [ 'python', 'confirm-dep-files.py', '<(_outputs)' ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ }],
+ },
+
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/actions/src/confirm-dep-files.py b/Source/ThirdParty/gyp/test/actions/src/confirm-dep-files.py
new file mode 100644
index 000000000..34efe28f1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/confirm-dep-files.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+
+# Confirm presence of files generated by our targets we depend on.
+# If they exist, create a new file.
+#
+# Note target's input files are explicitly NOT defined in the gyp file
+# so they can't easily be passed to this script as args.
+
+import os
+import sys
+
+outfile = sys.argv[1] # Example value we expect: deps_all_done_first_123.txt
+if (os.path.exists("dep_1.txt") and
+ os.path.exists("dep_2.txt") and
+ os.path.exists("dep_3.txt")):
+ open(outfile, "w")
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir1/counter.py b/Source/ThirdParty/gyp/test/actions/src/subdir1/counter.py
new file mode 100644
index 000000000..3612d7d2b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir1/counter.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+import time
+
+output = sys.argv[1]
+persistoutput = "%s.persist" % sys.argv[1]
+
+count = 0
+try:
+ count = open(persistoutput, 'r').read()
+except:
+ pass
+count = int(count) + 1
+
+if len(sys.argv) > 2:
+ max_count = int(sys.argv[2])
+ if count > max_count:
+ count = max_count
+
+oldcount = 0
+try:
+ oldcount = open(output, 'r').read()
+except:
+ pass
+
+# Save the count in a file that is undeclared, and thus hidden, to gyp. We need
+# to do this because, prior to running commands, scons deletes any declared
+# outputs, so we would lose our count if we just wrote to the given output file.
+# (The other option is to use Precious() in the scons generator, but that seems
+# too heavy-handed just to support this somewhat unrealistic test case, and
+# might lead to unintended side-effects).
+open(persistoutput, 'w').write('%d' % (count))
+
+# Only write the given output file if the count has changed.
+if int(oldcount) != count:
+ open(output, 'w').write('%d' % (count))
+ # Sleep so the next run changes the file time sufficiently to make the build
+ # detect the file as changed.
+ time.sleep(1)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir1/executable.gyp b/Source/ThirdParty/gyp/test/actions/src/subdir1/executable.gyp
new file mode 100644
index 000000000..6a1ce4f91
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir1/executable.gyp
@@ -0,0 +1,74 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'program.c',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'make-prog1',
+ 'inputs': [
+ 'make-prog1.py',
+ ],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/prog1.c',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ {
+ 'action_name': 'make-prog2',
+ 'inputs': [
+ 'make-prog2.py',
+ ],
+ 'outputs': [
+ 'actions-out/prog2.c',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ {
+ 'target_name': 'counter',
+ 'type': 'none',
+ 'actions': [
+ {
+ # This action should always run, regardless of whether or not it's
+ # inputs or the command-line change. We do this by creating a dummy
+ # first output, which is always missing, thus causing the build to
+ # always try to recreate it. Actual output files should be listed
+ # after the dummy one, and dependent targets should list the real
+ # output(s) in their inputs
+ # (see '../actions.gyp:depend_on_always_run_action').
+ 'action_name': 'action_counter',
+ 'inputs': [
+ 'counter.py',
+ ],
+ 'outputs': [
+ 'actions-out/action-counter.txt.always',
+ 'actions-out/action-counter.txt',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', 'actions-out/action-counter.txt', '2',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir1/make-prog1.py b/Source/ThirdParty/gyp/test/actions/src/subdir1/make-prog1.py
new file mode 100644
index 000000000..7ea1d8a2d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir1/make-prog1.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = r"""
+#include <stdio.h>
+
+void prog1(void)
+{
+ printf("Hello from make-prog1.py\n");
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir1/make-prog2.py b/Source/ThirdParty/gyp/test/actions/src/subdir1/make-prog2.py
new file mode 100644
index 000000000..0bfe4973c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir1/make-prog2.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = r"""
+#include <stdio.h>
+
+void prog2(void)
+{
+ printf("Hello from make-prog2.py\n");
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir1/program.c b/Source/ThirdParty/gyp/test/actions/src/subdir1/program.c
new file mode 100644
index 000000000..d5f661d90
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir1/program.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern void prog1(void);
+extern void prog2(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from program.c\n");
+ prog1();
+ prog2();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir2/make-file.py b/Source/ThirdParty/gyp/test/actions/src/subdir2/make-file.py
new file mode 100644
index 000000000..fff065314
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir2/make-file.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = "Hello from make-file.py\n"
+
+open(sys.argv[1], 'wb').write(contents)
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir2/none.gyp b/Source/ThirdParty/gyp/test/actions/src/subdir2/none.gyp
new file mode 100644
index 000000000..2caa97d55
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir2/none.gyp
@@ -0,0 +1,33 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'file',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'actions': [
+ {
+ 'action_name': 'make-file',
+ 'inputs': [
+ 'make-file.py',
+ ],
+ 'outputs': [
+ 'file.out',
+ # TODO: enhance testing infrastructure to test this
+ # without having to hard-code the intermediate dir paths.
+ #'<(INTERMEDIATE_DIR)/file.out',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ }
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir3/generate_main.py b/Source/ThirdParty/gyp/test/actions/src/subdir3/generate_main.py
new file mode 100644
index 000000000..b90b3aa6d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir3/generate_main.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = """
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from generate_main.py\\n");
+ return 0;
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/actions/src/subdir3/null_input.gyp b/Source/ThirdParty/gyp/test/actions/src/subdir3/null_input.gyp
new file mode 100644
index 000000000..9b0bea5fd
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/actions/src/subdir3/null_input.gyp
@@ -0,0 +1,29 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'null_input',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'actions': [
+ {
+ 'action_name': 'generate_main',
+ 'process_outputs_as_sources': 1,
+ 'inputs': [],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/main.c',
+ ],
+ 'action': [
+ # TODO: we can't just use <(_outputs) here?!
+ 'python', 'generate_main.py', '<(INTERMEDIATE_DIR)/main.c',
+ ],
+ # Allows the test to run without hermetic cygwin on windows.
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/additional-targets/gyptest-additional.py b/Source/ThirdParty/gyp/test/additional-targets/gyptest-additional.py
new file mode 100644
index 000000000..02e7d7a41
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/additional-targets/gyptest-additional.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple actions when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+
+# Build all.
+test.build('all.gyp', chdir='relocate/src')
+
+if test.format=='xcode':
+ chdir = 'relocate/src/dir1'
+else:
+ chdir = 'relocate/src'
+
+# Output is as expected.
+file_content = 'Hello from emit.py\n'
+test.built_file_must_match('out2.txt', file_content, chdir=chdir)
+
+test.built_file_must_not_exist('out.txt', chdir='relocate/src')
+test.built_file_must_not_exist('foolib1',
+ type=test.SHARED_LIB,
+ chdir=chdir)
+
+# TODO(mmoss) Make consistent with scons, with 'dir1' before 'out/Default'?
+if test.format == 'make':
+ chdir='relocate/src'
+else:
+ chdir='relocate/src/dir1'
+
+# Build the action explicitly.
+test.build('actions.gyp', 'action1_target', chdir=chdir)
+
+# Check that things got run.
+file_content = 'Hello from emit.py\n'
+test.built_file_must_exist('out.txt', chdir=chdir)
+
+# Build the shared library explicitly.
+test.build('actions.gyp', 'foolib1', chdir=chdir)
+
+test.built_file_must_exist('foolib1',
+ type=test.SHARED_LIB,
+ chdir=chdir)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/additional-targets/src/all.gyp b/Source/ThirdParty/gyp/test/additional-targets/src/all.gyp
new file mode 100644
index 000000000..21c83080a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/additional-targets/src/all.gyp
@@ -0,0 +1,13 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'all_targets',
+ 'type': 'none',
+ 'dependencies': ['dir1/actions.gyp:*'],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/additional-targets/src/dir1/actions.gyp b/Source/ThirdParty/gyp/test/additional-targets/src/dir1/actions.gyp
new file mode 100644
index 000000000..5089c8091
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/additional-targets/src/dir1/actions.gyp
@@ -0,0 +1,56 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'action1_target',
+ 'type': 'none',
+ 'suppress_wildcard': 1,
+ 'actions': [
+ {
+ 'action_name': 'action1',
+ 'inputs': [
+ 'emit.py',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/out.txt',
+ ],
+ 'action': ['python', 'emit.py', '<(PRODUCT_DIR)/out.txt'],
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ {
+ 'target_name': 'action2_target',
+ 'type': 'none',
+ 'actions': [
+ {
+ 'action_name': 'action2',
+ 'inputs': [
+ 'emit.py',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/out2.txt',
+ ],
+ 'action': ['python', 'emit.py', '<(PRODUCT_DIR)/out2.txt'],
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ {
+ 'target_name': 'foolib1',
+ 'type': 'shared_library',
+ 'suppress_wildcard': 1,
+ 'sources': ['lib1.c'],
+ },
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'target_defaults': {
+ 'cflags': ['-fPIC'],
+ },
+ }],
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/additional-targets/src/dir1/emit.py b/Source/ThirdParty/gyp/test/additional-targets/src/dir1/emit.py
new file mode 100644
index 000000000..5638c43b5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/additional-targets/src/dir1/emit.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+f = open(sys.argv[1], 'wb')
+f.write('Hello from emit.py\n')
+f.close()
diff --git a/Source/ThirdParty/gyp/test/additional-targets/src/dir1/lib1.c b/Source/ThirdParty/gyp/test/additional-targets/src/dir1/lib1.c
new file mode 100644
index 000000000..df4cb10f7
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/additional-targets/src/dir1/lib1.c
@@ -0,0 +1,6 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int func1(void) {
+ return 42;
+}
diff --git a/Source/ThirdParty/gyp/test/assembly/gyptest-assembly.py b/Source/ThirdParty/gyp/test/assembly/gyptest-assembly.py
new file mode 100644
index 000000000..40d0a062f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/assembly/gyptest-assembly.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that .hpp files are ignored when included in the source list on all
+platforms.
+"""
+
+import sys
+import TestGyp
+
+# TODO(bradnelson): get this working for windows.
+test = TestGyp.TestGyp(formats=['make', 'scons', 'xcode'])
+
+test.run_gyp('assembly.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('assembly.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Got 42.
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/assembly/src/as.bat b/Source/ThirdParty/gyp/test/assembly/src/as.bat
new file mode 100644
index 000000000..0a47382cb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/assembly/src/as.bat
@@ -0,0 +1,4 @@
+@echo off
+:: Mock windows assembler.
+cl /c %1 /Fo"%2"
+
diff --git a/Source/ThirdParty/gyp/test/assembly/src/assembly.gyp b/Source/ThirdParty/gyp/test/assembly/src/assembly.gyp
new file mode 100644
index 000000000..872dd5ec0
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/assembly/src/assembly.gyp
@@ -0,0 +1,59 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'conditions': [
+ ['OS=="win"', {
+ 'defines': ['PLATFORM_WIN'],
+ }],
+ ['OS=="mac"', {
+ 'defines': ['PLATFORM_MAC'],
+ }],
+ ['OS=="linux"', {
+ 'defines': ['PLATFORM_LINUX'],
+ }],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'dependencies': ['lib1'],
+ 'sources': [
+ 'program.c',
+ ],
+ },
+ {
+ 'target_name': 'lib1',
+ 'type': 'static_library',
+ 'sources': [
+ 'lib1.S',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'target_defaults': {
+ 'rules': [
+ {
+ 'rule_name': 'assembler',
+ 'msvs_cygwin_shell': 0,
+ 'extension': 'S',
+ 'inputs': [
+ 'as.bat',
+ ],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).obj',
+ ],
+ 'action':
+ ['as.bat', 'lib1.c', '<(_outputs)'],
+ 'message': 'Building assembly file <(RULE_INPUT_PATH)',
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ },],
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/assembly/src/lib1.S b/Source/ThirdParty/gyp/test/assembly/src/lib1.S
new file mode 100644
index 000000000..e7102bf24
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/assembly/src/lib1.S
@@ -0,0 +1,10 @@
+#if PLATFORM_WINDOWS || PLATFORM_MAC
+# define IDENTIFIER(n) _##n
+#else /* Linux */
+# define IDENTIFIER(n) n
+#endif
+
+.globl IDENTIFIER(lib1_function)
+IDENTIFIER(lib1_function):
+ movl $42, %eax
+ ret
diff --git a/Source/ThirdParty/gyp/test/assembly/src/lib1.c b/Source/ThirdParty/gyp/test/assembly/src/lib1.c
new file mode 100644
index 000000000..be21ecd5f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/assembly/src/lib1.c
@@ -0,0 +1,3 @@
+int lib1_function(void) {
+ return 42;
+}
diff --git a/Source/ThirdParty/gyp/test/assembly/src/program.c b/Source/ThirdParty/gyp/test/assembly/src/program.c
new file mode 100644
index 000000000..ecce3b0bb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/assembly/src/program.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern int lib1_function(void);
+
+int main(int argc, char *argv[])
+{
+ fprintf(stdout, "Hello from program.c\n");
+ fflush(stdout);
+ fprintf(stdout, "Got %d.\n", lib1_function());
+ fflush(stdout);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/gyptest-all.py b/Source/ThirdParty/gyp/test/builddir/gyptest-all.py
new file mode 100644
index 000000000..324d7fc73
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/gyptest-all.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify the settings that cause a set of programs to be created in
+a specific build directory, and that no intermediate built files
+get created outside of that build directory hierarchy even when
+referred to with deeply-nested ../../.. paths.
+"""
+
+import TestGyp
+
+# TODO(mmoss): Make only supports (theoretically) a single, global build
+# directory (through GYP_GENERATOR_FLAGS 'output_dir'), rather than
+# gyp-file-specific settings (e.g. the stuff in builddir.gypi) that the other
+# generators support, so this doesn't work yet for make.
+# TODO(mmoss) Make also has the issue that the top-level Makefile is written to
+# the "--depth" location, which is one level above 'src', but then this test
+# moves 'src' somewhere else, leaving the Makefile behind, so make can't find
+# its sources. I'm not sure if make is wrong for writing outside the current
+# directory, or if the test is wrong for assuming everything generated is under
+# the current directory.
+test = TestGyp.TestGyp(formats=['!make'])
+
+test.run_gyp('prog1.gyp', '--depth=..', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.subdir('relocate/builddir')
+
+# Make sure that all the built ../../etc. files only get put under builddir,
+# by making all of relocate read-only and then making only builddir writable.
+test.writable('relocate', False)
+test.writable('relocate/builddir', True)
+
+# Suppress the test infrastructure's setting SYMROOT on the command line.
+test.build('prog1.gyp', test.ALL, SYMROOT=None, chdir='relocate/src')
+
+expect1 = """\
+Hello from prog1.c
+Hello from func1.c
+"""
+
+expect2 = """\
+Hello from subdir2/prog2.c
+Hello from func2.c
+"""
+
+expect3 = """\
+Hello from subdir2/subdir3/prog3.c
+Hello from func3.c
+"""
+
+expect4 = """\
+Hello from subdir2/subdir3/subdir4/prog4.c
+Hello from func4.c
+"""
+
+expect5 = """\
+Hello from subdir2/subdir3/subdir4/subdir5/prog5.c
+Hello from func5.c
+"""
+
+def run_builddir(prog, expect):
+ dir = 'relocate/builddir/Default/'
+ test.run(program=test.workpath(dir + prog), stdout=expect)
+
+run_builddir('prog1', expect1)
+run_builddir('prog2', expect2)
+run_builddir('prog3', expect3)
+run_builddir('prog4', expect4)
+run_builddir('prog5', expect5)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/builddir/gyptest-default.py b/Source/ThirdParty/gyp/test/builddir/gyptest-default.py
new file mode 100644
index 000000000..6171d1597
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/gyptest-default.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify the settings that cause a set of programs to be created in
+a specific build directory, and that no intermediate built files
+get created outside of that build directory hierarchy even when
+referred to with deeply-nested ../../.. paths.
+"""
+
+import TestGyp
+
+# TODO(mmoss): Make only supports (theoretically) a single, global build
+# directory (through GYP_GENERATOR_FLAGS 'output_dir'), rather than
+# gyp-file-specific settings (e.g. the stuff in builddir.gypi) that the other
+# generators support, so this doesn't work yet for make.
+# TODO(mmoss) Make also has the issue that the top-level Makefile is written to
+# the "--depth" location, which is one level above 'src', but then this test
+# moves 'src' somewhere else, leaving the Makefile behind, so make can't find
+# its sources. I'm not sure if make is wrong for writing outside the current
+# directory, or if the test is wrong for assuming everything generated is under
+# the current directory.
+test = TestGyp.TestGyp(formats=['!make'])
+
+test.run_gyp('prog1.gyp', '--depth=..', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.subdir('relocate/builddir')
+
+# Make sure that all the built ../../etc. files only get put under builddir,
+# by making all of relocate read-only and then making only builddir writable.
+test.writable('relocate', False)
+test.writable('relocate/builddir', True)
+
+# Suppress the test infrastructure's setting SYMROOT on the command line.
+test.build('prog1.gyp', SYMROOT=None, chdir='relocate/src')
+
+expect1 = """\
+Hello from prog1.c
+Hello from func1.c
+"""
+
+expect2 = """\
+Hello from subdir2/prog2.c
+Hello from func2.c
+"""
+
+expect3 = """\
+Hello from subdir2/subdir3/prog3.c
+Hello from func3.c
+"""
+
+expect4 = """\
+Hello from subdir2/subdir3/subdir4/prog4.c
+Hello from func4.c
+"""
+
+expect5 = """\
+Hello from subdir2/subdir3/subdir4/subdir5/prog5.c
+Hello from func5.c
+"""
+
+def run_builddir(prog, expect):
+ dir = 'relocate/builddir/Default/'
+ test.run(program=test.workpath(dir + prog), stdout=expect)
+
+run_builddir('prog1', expect1)
+run_builddir('prog2', expect2)
+run_builddir('prog3', expect3)
+run_builddir('prog4', expect4)
+run_builddir('prog5', expect5)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/builddir/src/builddir.gypi b/Source/ThirdParty/gyp/test/builddir/src/builddir.gypi
new file mode 100644
index 000000000..e3c61475b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/builddir.gypi
@@ -0,0 +1,21 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'configurations': {
+ 'Default': {
+ 'msvs_configuration_attributes': {
+ 'OutputDirectory': '<(DEPTH)\\builddir\Default',
+ },
+ },
+ },
+ },
+ 'scons_settings': {
+ 'sconsbuild_dir': '<(DEPTH)/builddir',
+ },
+ 'xcode_settings': {
+ 'SYMROOT': '<(DEPTH)/builddir',
+ },
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/func1.c b/Source/ThirdParty/gyp/test/builddir/src/func1.c
new file mode 100644
index 000000000..b8e6a0695
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/func1.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func1(void)
+{
+ printf("Hello from func1.c\n");
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/func2.c b/Source/ThirdParty/gyp/test/builddir/src/func2.c
new file mode 100644
index 000000000..14aabac47
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/func2.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func2(void)
+{
+ printf("Hello from func2.c\n");
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/func3.c b/Source/ThirdParty/gyp/test/builddir/src/func3.c
new file mode 100644
index 000000000..3b4edeae6
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/func3.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func3(void)
+{
+ printf("Hello from func3.c\n");
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/func4.c b/Source/ThirdParty/gyp/test/builddir/src/func4.c
new file mode 100644
index 000000000..732891b79
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/func4.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func4(void)
+{
+ printf("Hello from func4.c\n");
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/func5.c b/Source/ThirdParty/gyp/test/builddir/src/func5.c
new file mode 100644
index 000000000..18fdfabbb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/func5.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func5(void)
+{
+ printf("Hello from func5.c\n");
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/prog1.c b/Source/ThirdParty/gyp/test/builddir/src/prog1.c
new file mode 100644
index 000000000..674ca747b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/prog1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func1(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog1.c\n");
+ func1();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/prog1.gyp b/Source/ThirdParty/gyp/test/builddir/src/prog1.gyp
new file mode 100644
index 000000000..5b96f035e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/prog1.gyp
@@ -0,0 +1,30 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ 'builddir.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'pull_in_all',
+ 'type': 'none',
+ 'dependencies': [
+ 'prog1',
+ 'subdir2/prog2.gyp:prog2',
+ 'subdir2/subdir3/prog3.gyp:prog3',
+ 'subdir2/subdir3/subdir4/prog4.gyp:prog4',
+ 'subdir2/subdir3/subdir4/subdir5/prog5.gyp:prog5',
+ ],
+ },
+ {
+ 'target_name': 'prog1',
+ 'type': 'executable',
+ 'sources': [
+ 'prog1.c',
+ 'func1.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/subdir2/prog2.c b/Source/ThirdParty/gyp/test/builddir/src/subdir2/prog2.c
new file mode 100644
index 000000000..bbdf4f060
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/subdir2/prog2.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func2(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from subdir2/prog2.c\n");
+ func2();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/subdir2/prog2.gyp b/Source/ThirdParty/gyp/test/builddir/src/subdir2/prog2.gyp
new file mode 100644
index 000000000..96299b646
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/subdir2/prog2.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../builddir.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog2',
+ 'type': 'executable',
+ 'sources': [
+ 'prog2.c',
+ '../func2.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/prog3.c b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/prog3.c
new file mode 100644
index 000000000..10c530b23
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/prog3.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func3(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from subdir2/subdir3/prog3.c\n");
+ func3();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp
new file mode 100644
index 000000000..d7df43c7b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/prog3.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../../builddir.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog3',
+ 'type': 'executable',
+ 'sources': [
+ 'prog3.c',
+ '../../func3.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c
new file mode 100644
index 000000000..dcba9a9d4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func4(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from subdir2/subdir3/subdir4/prog4.c\n");
+ func4();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp
new file mode 100644
index 000000000..862a8a18c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/prog4.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../../../builddir.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog4',
+ 'type': 'executable',
+ 'sources': [
+ 'prog4.c',
+ '../../../func4.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c
new file mode 100644
index 000000000..69132e576
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void func5(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from subdir2/subdir3/subdir4/subdir5/prog5.c\n");
+ func5();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp
new file mode 100644
index 000000000..fe1c9cbf5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/builddir/src/subdir2/subdir3/subdir4/subdir5/prog5.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../../../../builddir.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog5',
+ 'type': 'executable',
+ 'sources': [
+ 'prog5.c',
+ '../../../../func5.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/cflags/cflags.c b/Source/ThirdParty/gyp/test/cflags/cflags.c
new file mode 100644
index 000000000..c1e245207
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/cflags/cflags.c
@@ -0,0 +1,15 @@
+/* Copyright (c) 2010 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+#ifdef __OPTIMIZE__
+ printf("Using an optimization flag\n");
+#else
+ printf("Using no optimization flag\n");
+#endif
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/cflags/cflags.gyp b/Source/ThirdParty/gyp/test/cflags/cflags.gyp
new file mode 100644
index 000000000..9003fb167
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/cflags/cflags.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'cflags',
+ 'type': 'executable',
+ 'opt': '-Os',
+ 'sources': [
+ 'cflags.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/cflags/gyptest-cflags.py b/Source/ThirdParty/gyp/test/cflags/gyptest-cflags.py
new file mode 100644
index 000000000..acc424a2c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/cflags/gyptest-cflags.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ define specified by a gyp define, and
+the use of the environment during regeneration when the gyp file changes.
+"""
+
+import os
+import TestGyp
+
+env_stack = []
+
+
+def PushEnv():
+ env_copy = os.environ.copy()
+ env_stack.append(env_copy)
+
+def PopEnv():
+ os.eniron=env_stack.pop()
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+try:
+ PushEnv()
+ os.environ['CFLAGS'] = '-O0'
+ test.run_gyp('cflags.gyp')
+finally:
+ # We clear the environ after calling gyp. When the auto-regeneration happens,
+ # the same define should be reused anyway. Reset to empty string first in
+ # case the platform doesn't support unsetenv.
+ PopEnv()
+
+test.build('cflags.gyp')
+
+expect = """\
+Using no optimization flag
+"""
+test.run_built_executable('cflags', stdout=expect)
+
+test.sleep()
+
+try:
+ PushEnv()
+ os.environ['CFLAGS'] = '-O2'
+ test.run_gyp('cflags.gyp')
+finally:
+ # We clear the environ after calling gyp. When the auto-regeneration happens,
+ # the same define should be reused anyway. Reset to empty string first in
+ # case the platform doesn't support unsetenv.
+ PopEnv()
+
+test.build('cflags.gyp')
+
+expect = """\
+Using an optimization flag
+"""
+test.run_built_executable('cflags', stdout=expect)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/compilable/gyptest-headers.py b/Source/ThirdParty/gyp/test/compilable/gyptest-headers.py
new file mode 100644
index 000000000..91760216f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/compilable/gyptest-headers.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that .hpp files are ignored when included in the source list on all
+platforms.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('headers.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('headers.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from lib1.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/compilable/src/headers.gyp b/Source/ThirdParty/gyp/test/compilable/src/headers.gyp
new file mode 100644
index 000000000..b6c2a8857
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/compilable/src/headers.gyp
@@ -0,0 +1,26 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'dependencies': [
+ 'lib1'
+ ],
+ 'sources': [
+ 'program.cpp',
+ ],
+ },
+ {
+ 'target_name': 'lib1',
+ 'type': 'static_library',
+ 'sources': [
+ 'lib1.hpp',
+ 'lib1.cpp',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/compilable/src/lib1.cpp b/Source/ThirdParty/gyp/test/compilable/src/lib1.cpp
new file mode 100644
index 000000000..51bc31a40
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/compilable/src/lib1.cpp
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "lib1.hpp"
+
+void lib1_function(void) {
+ fprintf(stdout, "Hello from lib1.c\n");
+ fflush(stdout);
+}
diff --git a/Source/ThirdParty/gyp/test/compilable/src/lib1.hpp b/Source/ThirdParty/gyp/test/compilable/src/lib1.hpp
new file mode 100644
index 000000000..72e63e8ac
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/compilable/src/lib1.hpp
@@ -0,0 +1,6 @@
+#ifndef _lib1_hpp
+#define _lib1_hpp
+
+extern void lib1_function(void);
+
+#endif
diff --git a/Source/ThirdParty/gyp/test/compilable/src/program.cpp b/Source/ThirdParty/gyp/test/compilable/src/program.cpp
new file mode 100644
index 000000000..81420bad4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/compilable/src/program.cpp
@@ -0,0 +1,9 @@
+#include <stdio.h>
+#include "lib1.hpp"
+
+int main(int argc, char *argv[]) {
+ fprintf(stdout, "Hello from program.c\n");
+ fflush(stdout);
+ lib1_function();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/basics/configurations.c b/Source/ThirdParty/gyp/test/configurations/basics/configurations.c
new file mode 100644
index 000000000..6c1f90016
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/basics/configurations.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+#ifdef FOO
+ printf("Foo configuration\n");
+#endif
+#ifdef DEBUG
+ printf("Debug configuration\n");
+#endif
+#ifdef RELEASE
+ printf("Release configuration\n");
+#endif
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/basics/configurations.gyp b/Source/ThirdParty/gyp/test/configurations/basics/configurations.gyp
new file mode 100644
index 000000000..93f1d8d5c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/basics/configurations.gyp
@@ -0,0 +1,32 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'executable',
+ 'sources': [
+ 'configurations.c',
+ ],
+ 'configurations': {
+ 'Debug': {
+ 'defines': [
+ 'DEBUG',
+ ],
+ },
+ 'Release': {
+ 'defines': [
+ 'RELEASE',
+ ],
+ },
+ 'Foo': {
+ 'defines': [
+ 'FOO',
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/basics/gyptest-configurations.py b/Source/ThirdParty/gyp/test/configurations/basics/gyptest-configurations.py
new file mode 100644
index 000000000..27cd2e87d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/basics/gyptest-configurations.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable in three different configurations.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('configurations.gyp')
+
+test.set_configuration('Release')
+test.build('configurations.gyp')
+test.run_built_executable('configurations', stdout="Release configuration\n")
+
+test.set_configuration('Debug')
+test.build('configurations.gyp')
+test.run_built_executable('configurations', stdout="Debug configuration\n")
+
+test.set_configuration('Foo')
+test.build('configurations.gyp')
+test.run_built_executable('configurations', stdout="Foo configuration\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/configurations/inheritance/configurations.c b/Source/ThirdParty/gyp/test/configurations/inheritance/configurations.c
new file mode 100644
index 000000000..2d5565eeb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/inheritance/configurations.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+#ifdef BASE
+ printf("Base configuration\n");
+#endif
+#ifdef COMMON
+ printf("Common configuration\n");
+#endif
+#ifdef COMMON2
+ printf("Common2 configuration\n");
+#endif
+#ifdef DEBUG
+ printf("Debug configuration\n");
+#endif
+#ifdef RELEASE
+ printf("Release configuration\n");
+#endif
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/inheritance/configurations.gyp b/Source/ThirdParty/gyp/test/configurations/inheritance/configurations.gyp
new file mode 100644
index 000000000..9441376b4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/inheritance/configurations.gyp
@@ -0,0 +1,40 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'configurations': {
+ 'Base': {
+ 'abstract': 1,
+ 'defines': ['BASE'],
+ },
+ 'Common': {
+ 'abstract': 1,
+ 'inherit_from': ['Base'],
+ 'defines': ['COMMON'],
+ },
+ 'Common2': {
+ 'abstract': 1,
+ 'defines': ['COMMON2'],
+ },
+ 'Debug': {
+ 'inherit_from': ['Common', 'Common2'],
+ 'defines': ['DEBUG'],
+ },
+ 'Release': {
+ 'inherit_from': ['Common', 'Common2'],
+ 'defines': ['RELEASE'],
+ },
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'executable',
+ 'sources': [
+ 'configurations.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/inheritance/gyptest-inheritance.py b/Source/ThirdParty/gyp/test/configurations/inheritance/gyptest-inheritance.py
new file mode 100644
index 000000000..22c73a375
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/inheritance/gyptest-inheritance.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable in three different configurations.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('configurations.gyp')
+
+test.set_configuration('Release')
+test.build('configurations.gyp')
+test.run_built_executable('configurations',
+ stdout=('Base configuration\n'
+ 'Common configuration\n'
+ 'Common2 configuration\n'
+ 'Release configuration\n'))
+
+test.set_configuration('Debug')
+test.build('configurations.gyp')
+test.run_built_executable('configurations',
+ stdout=('Base configuration\n'
+ 'Common configuration\n'
+ 'Common2 configuration\n'
+ 'Debug configuration\n'))
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/actions.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/actions.gyp
new file mode 100644
index 000000000..a6e42089e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/actions.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'actions': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/all_dependent_settings.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/all_dependent_settings.gyp
new file mode 100644
index 000000000..b16a245df
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/all_dependent_settings.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'all_dependent_settings': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/configurations.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/configurations.gyp
new file mode 100644
index 000000000..2cfc96004
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/configurations.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'configurations': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/dependencies.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/dependencies.gyp
new file mode 100644
index 000000000..74633f3f1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/dependencies.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'dependencies': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/direct_dependent_settings.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/direct_dependent_settings.gyp
new file mode 100644
index 000000000..8a0f2e95e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/direct_dependent_settings.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'direct_dependent_settings': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/gyptest-configurations.py b/Source/ThirdParty/gyp/test/configurations/invalid/gyptest-configurations.py
new file mode 100644
index 000000000..d76cdedb0
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/gyptest-configurations.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable in three different configurations.
+"""
+
+import TestGyp
+
+# Keys that do not belong inside a configuration dictionary.
+invalid_configuration_keys = [
+ 'actions',
+ 'all_dependent_settings',
+ 'configurations',
+ 'dependencies',
+ 'direct_dependent_settings',
+ 'libraries',
+ 'link_settings',
+ 'sources',
+ 'target_name',
+ 'type',
+]
+
+test = TestGyp.TestGyp()
+
+if test.format == 'scons':
+ test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n')
+
+for test_key in invalid_configuration_keys:
+ test.run_gyp('%s.gyp' % test_key, status=1, stderr=None)
+ expect = ['%s not allowed in the Debug configuration, found in target '
+ '%s.gyp:configurations#target' % (test_key, test_key)]
+ test.must_contain_all_lines(test.stderr(), expect)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/libraries.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/libraries.gyp
new file mode 100644
index 000000000..c4014ed40
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/libraries.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'libraries': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/link_settings.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/link_settings.gyp
new file mode 100644
index 000000000..2f0e1c46f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/link_settings.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'link_settings': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/sources.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/sources.gyp
new file mode 100644
index 000000000..b38cca038
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/sources.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'sources': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/target_name.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/target_name.gyp
new file mode 100644
index 000000000..83baad95d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/target_name.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'target_name': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/invalid/type.gyp b/Source/ThirdParty/gyp/test/configurations/invalid/type.gyp
new file mode 100644
index 000000000..bc55898b8
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/invalid/type.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'none',
+ 'configurations': {
+ 'Debug': {
+ 'type': [
+ ],
+ },
+ }
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/target_platform/configurations.gyp b/Source/ThirdParty/gyp/test/configurations/target_platform/configurations.gyp
new file mode 100644
index 000000000..d15429f4e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/target_platform/configurations.gyp
@@ -0,0 +1,58 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'configurations': {
+ 'Debug_Win32': {
+ 'msvs_configuration_platform': 'Win32',
+ },
+ 'Debug_x64': {
+ 'msvs_configuration_platform': 'x64',
+ },
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'left',
+ 'type': 'static_library',
+ 'sources': [
+ 'left.c',
+ ],
+ 'configurations': {
+ 'Debug_Win32': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ },
+ {
+ 'target_name': 'right',
+ 'type': 'static_library',
+ 'sources': [
+ 'right.c',
+ ],
+ },
+ {
+ 'target_name': 'front_left',
+ 'type': 'executable',
+ 'dependencies': ['left'],
+ 'sources': [
+ 'front.c',
+ ],
+ 'configurations': {
+ 'Debug_Win32': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ },
+ {
+ 'target_name': 'front_right',
+ 'type': 'executable',
+ 'dependencies': ['right'],
+ 'sources': [
+ 'front.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/target_platform/front.c b/Source/ThirdParty/gyp/test/configurations/target_platform/front.c
new file mode 100644
index 000000000..12b1d0aa3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/target_platform/front.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+const char *message(void);
+
+int main(int argc, char *argv[]) {
+ printf("%s\n", message());
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/target_platform/gyptest-target_platform.py b/Source/ThirdParty/gyp/test/configurations/target_platform/gyptest-target_platform.py
new file mode 100644
index 000000000..ae4e9e5a2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/target_platform/gyptest-target_platform.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests the msvs specific msvs_target_platform option.
+"""
+
+import TestGyp
+import TestCommon
+
+
+def RunX64(exe, stdout):
+ try:
+ test.run_built_executable(exe, stdout=stdout)
+ except WindowsError, e:
+ # Assume the exe is 64-bit if it can't load on 32-bit systems.
+ # Both versions of the error are required because different versions
+ # of python seem to return different errors for invalid exe type.
+ if e.errno != 193 and '[Error 193]' not in str(e):
+ raise
+
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('configurations.gyp')
+
+test.set_configuration('Debug|x64')
+test.build('configurations.gyp', rebuild=True)
+RunX64('front_left', stdout=('left\n'))
+RunX64('front_right', stdout=('right\n'))
+
+test.set_configuration('Debug|Win32')
+test.build('configurations.gyp', rebuild=True)
+RunX64('front_left', stdout=('left\n'))
+test.run_built_executable('front_right', stdout=('right\n'))
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/configurations/target_platform/left.c b/Source/ThirdParty/gyp/test/configurations/target_platform/left.c
new file mode 100644
index 000000000..1ce2ea122
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/target_platform/left.c
@@ -0,0 +1,3 @@
+const char *message(void) {
+ return "left";
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/target_platform/right.c b/Source/ThirdParty/gyp/test/configurations/target_platform/right.c
new file mode 100644
index 000000000..b1578492f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/target_platform/right.c
@@ -0,0 +1,3 @@
+const char *message(void) {
+ return "right";
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/x64/configurations.c b/Source/ThirdParty/gyp/test/configurations/x64/configurations.c
new file mode 100644
index 000000000..72c97e31d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/x64/configurations.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[]) {
+ if (sizeof(void*) == 4) {
+ printf("Running Win32\n");
+ } else if (sizeof(void*) == 8) {
+ printf("Running x64\n");
+ } else {
+ printf("Unexpected platform\n");
+ }
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/x64/configurations.gyp b/Source/ThirdParty/gyp/test/configurations/x64/configurations.gyp
new file mode 100644
index 000000000..06ffa3758
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/x64/configurations.gyp
@@ -0,0 +1,26 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'configurations': {
+ 'Debug': {
+ 'msvs_configuration_platform': 'Win32',
+ },
+ 'Debug_x64': {
+ 'inherit_from': ['Debug'],
+ 'msvs_configuration_platform': 'x64',
+ },
+ },
+ },
+ 'targets': [
+ {
+ 'target_name': 'configurations',
+ 'type': 'executable',
+ 'sources': [
+ 'configurations.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/configurations/x64/gyptest-x86.py b/Source/ThirdParty/gyp/test/configurations/x64/gyptest-x86.py
new file mode 100644
index 000000000..254ea6fbc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/configurations/x64/gyptest-x86.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable in three different configurations.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('configurations.gyp')
+
+for platform in ['Win32', 'x64']:
+ test.set_configuration('Debug|%s' % platform)
+ test.build('configurations.gyp', rebuild=True)
+ try:
+ test.run_built_executable('configurations',
+ stdout=('Running %s\n' % platform))
+ except WindowsError, e:
+ # Assume the exe is 64-bit if it can't load on 32-bit systems.
+ if platform == 'x64' and (e.errno == 193 or '[Error 193]' in str(e)):
+ continue
+ raise
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/copies-link/gyptest-copies-link.py b/Source/ThirdParty/gyp/test/copies-link/gyptest-copies-link.py
new file mode 100644
index 000000000..fe7b6025c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies-link/gyptest-copies-link.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies using the build tool default.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies-link.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('copies-link.gyp', chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/copies-link/src/copies-link.gyp b/Source/ThirdParty/gyp/test/copies-link/src/copies-link.gyp
new file mode 100644
index 000000000..9d2530a6e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies-link/src/copies-link.gyp
@@ -0,0 +1,61 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'func1',
+ 'type': 'static_library',
+ 'sources': ['func1.c'],
+ },
+ {
+ 'target_name': 'clone_func1',
+ 'type': 'none',
+ 'dependencies': ['func1'],
+ 'actions': [
+ {
+ 'action_name': 'cloning library',
+ 'inputs': [
+ '<(LIB_DIR)/<(STATIC_LIB_PREFIX)func1<(STATIC_LIB_SUFFIX)'
+ ],
+ 'outputs': ['<(PRODUCT_DIR)/alternate/'
+ '<(STATIC_LIB_PREFIX)cloned<(STATIC_LIB_SUFFIX)'],
+ 'destination': '<(PRODUCT_DIR)',
+ 'action': ['python', 'copy.py', '<@(_inputs)', '<@(_outputs)'],
+ 'msvs_cygwin_shell': 0,
+ },
+ ],
+ },
+ {
+ 'target_name': 'copy_cloned',
+ 'type': 'none',
+ 'dependencies': ['clone_func1'],
+ 'copies': [
+ {
+ 'destination': '<(LIB_DIR)',
+ 'files': [
+ '<(PRODUCT_DIR)/alternate/'
+ '<(STATIC_LIB_PREFIX)cloned<(STATIC_LIB_SUFFIX)',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'use_cloned',
+ 'type': 'executable',
+ 'sources': ['main.c'],
+ 'dependencies': ['copy_cloned'],
+ 'link_settings': {
+ 'conditions': [
+ ['OS=="win"', {
+ 'libraries': ['-l"<(LIB_DIR)/cloned.lib"'],
+ }, {
+ 'libraries': ['-lcloned'],
+ 'ldflags': ['-L <(LIB_DIR)'],
+ }],
+ ],
+ },
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/copies-link/src/copy.py b/Source/ThirdParty/gyp/test/copies-link/src/copy.py
new file mode 100644
index 000000000..a1dd8718a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies-link/src/copy.py
@@ -0,0 +1,21 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import shutil
+import sys
+
+
+def main(argv):
+ if len(argv) != 3:
+ print 'USAGE: copy.py <src> <dst>'
+ return 1
+
+ shutil.copy(argv[1], argv[2])
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/Source/ThirdParty/gyp/test/copies-link/src/func1.c b/Source/ThirdParty/gyp/test/copies-link/src/func1.c
new file mode 100644
index 000000000..cceccdd66
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies-link/src/func1.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void func1(void) {
+ printf("hello from func1\n");
+}
diff --git a/Source/ThirdParty/gyp/test/copies-link/src/main.c b/Source/ThirdParty/gyp/test/copies-link/src/main.c
new file mode 100644
index 000000000..56fd2f04a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies-link/src/main.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+extern void func1(void);
+
+int main(int argc, char *argv[]) {
+ printf("hello from link1\n");
+ func1();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/copies/gyptest-all.py b/Source/ThirdParty/gyp/test/copies/gyptest-all.py
new file mode 100644
index 000000000..8542ab7b9
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/gyptest-all.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('copies.gyp', test.ALL, chdir='relocate/src')
+
+test.must_match(['relocate', 'src', 'copies-out', 'file1'], 'file1 contents\n')
+
+test.built_file_must_match('copies-out/file2',
+ 'file2 contents\n',
+ chdir='relocate/src')
+
+test.built_file_must_match('copies-out/directory/file3',
+ 'file3 contents\n',
+ chdir='relocate/src')
+test.built_file_must_match('copies-out/directory/file4',
+ 'file4 contents\n',
+ chdir='relocate/src')
+test.built_file_must_match('copies-out/directory/subdir/file5',
+ 'file5 contents\n',
+ chdir='relocate/src')
+test.built_file_must_match('copies-out/subdir/file6',
+ 'file6 contents\n',
+ chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/copies/gyptest-default.py b/Source/ThirdParty/gyp/test/copies/gyptest-default.py
new file mode 100644
index 000000000..a5d1bf9c3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/gyptest-default.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies using the build tool default.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('copies.gyp', chdir='relocate/src')
+
+test.must_match(['relocate', 'src', 'copies-out', 'file1'], 'file1 contents\n')
+
+test.built_file_must_match('copies-out/file2',
+ 'file2 contents\n',
+ chdir='relocate/src')
+
+test.built_file_must_match('copies-out/directory/file3',
+ 'file3 contents\n',
+ chdir='relocate/src')
+test.built_file_must_match('copies-out/directory/file4',
+ 'file4 contents\n',
+ chdir='relocate/src')
+test.built_file_must_match('copies-out/directory/subdir/file5',
+ 'file5 contents\n',
+ chdir='relocate/src')
+test.built_file_must_match('copies-out/subdir/file6',
+ 'file6 contents\n',
+ chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/copies/src/copies.gyp b/Source/ThirdParty/gyp/test/copies/src/copies.gyp
new file mode 100644
index 000000000..ce2e0cabc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/src/copies.gyp
@@ -0,0 +1,70 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'copies1',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': 'copies-out',
+ 'files': [
+ 'file1',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'copies2',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-out',
+ 'files': [
+ 'file2',
+ ],
+ },
+ ],
+ },
+ # Copy a directory tree.
+ {
+ 'target_name': 'copies_recursive',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-out',
+ 'files': [
+ 'directory/',
+ ],
+ },
+ ],
+ },
+ # Copy a directory from deeper in the tree (this should not reproduce the
+ # entire directory path in the destination, only the final directory).
+ {
+ 'target_name': 'copies_recursive_depth',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-out',
+ 'files': [
+ 'parentdir/subdir/',
+ ],
+ },
+ ],
+ },
+ # Verify that a null 'files' list doesn't gag the generators.
+ {
+ 'target_name': 'copies_null',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-null',
+ 'files': [],
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/copies/src/directory/file3 b/Source/ThirdParty/gyp/test/copies/src/directory/file3
new file mode 100644
index 000000000..43f16f352
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/src/directory/file3
@@ -0,0 +1 @@
+file3 contents
diff --git a/Source/ThirdParty/gyp/test/copies/src/directory/file4 b/Source/ThirdParty/gyp/test/copies/src/directory/file4
new file mode 100644
index 000000000..5f7270a08
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/src/directory/file4
@@ -0,0 +1 @@
+file4 contents
diff --git a/Source/ThirdParty/gyp/test/copies/src/directory/subdir/file5 b/Source/ThirdParty/gyp/test/copies/src/directory/subdir/file5
new file mode 100644
index 000000000..41f47186b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/src/directory/subdir/file5
@@ -0,0 +1 @@
+file5 contents
diff --git a/Source/ThirdParty/gyp/test/copies/src/file1 b/Source/ThirdParty/gyp/test/copies/src/file1
new file mode 100644
index 000000000..84d55c575
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/src/file1
@@ -0,0 +1 @@
+file1 contents
diff --git a/Source/ThirdParty/gyp/test/copies/src/file2 b/Source/ThirdParty/gyp/test/copies/src/file2
new file mode 100644
index 000000000..af1b8ae35
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/src/file2
@@ -0,0 +1 @@
+file2 contents
diff --git a/Source/ThirdParty/gyp/test/copies/src/parentdir/subdir/file6 b/Source/ThirdParty/gyp/test/copies/src/parentdir/subdir/file6
new file mode 100644
index 000000000..f5d575734
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/copies/src/parentdir/subdir/file6
@@ -0,0 +1 @@
+file6 contents
diff --git a/Source/ThirdParty/gyp/test/cxxflags/cxxflags.cc b/Source/ThirdParty/gyp/test/cxxflags/cxxflags.cc
new file mode 100644
index 000000000..c1e245207
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/cxxflags/cxxflags.cc
@@ -0,0 +1,15 @@
+/* Copyright (c) 2010 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+#ifdef __OPTIMIZE__
+ printf("Using an optimization flag\n");
+#else
+ printf("Using no optimization flag\n");
+#endif
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/cxxflags/cxxflags.gyp b/Source/ThirdParty/gyp/test/cxxflags/cxxflags.gyp
new file mode 100644
index 000000000..24d883aae
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/cxxflags/cxxflags.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'cxxflags',
+ 'type': 'executable',
+ 'opt': '-Os',
+ 'sources': [
+ 'cxxflags.cc',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/cxxflags/gyptest-cxxflags.py b/Source/ThirdParty/gyp/test/cxxflags/gyptest-cxxflags.py
new file mode 100644
index 000000000..2e5a6d947
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/cxxflags/gyptest-cxxflags.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ define specified by a gyp define, and
+the use of the environment during regeneration when the gyp file changes.
+"""
+
+import os
+import TestGyp
+
+env_stack = []
+
+
+def PushEnv():
+ env_copy = os.environ.copy()
+ env_stack.append(env_copy)
+
+def PopEnv():
+ os.eniron=env_stack.pop()
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+try:
+ PushEnv()
+ os.environ['CXXFLAGS'] = '-O0'
+ test.run_gyp('cxxflags.gyp')
+finally:
+ # We clear the environ after calling gyp. When the auto-regeneration happens,
+ # the same define should be reused anyway. Reset to empty string first in
+ # case the platform doesn't support unsetenv.
+ PopEnv()
+
+test.build('cxxflags.gyp')
+
+expect = """\
+Using no optimization flag
+"""
+test.run_built_executable('cxxflags', stdout=expect)
+
+test.sleep()
+
+try:
+ PushEnv()
+ os.environ['CXXFLAGS'] = '-O2'
+ test.run_gyp('cxxflags.gyp')
+finally:
+ # We clear the environ after calling gyp. When the auto-regeneration happens,
+ # the same define should be reused anyway. Reset to empty string first in
+ # case the platform doesn't support unsetenv.
+ PopEnv()
+
+test.build('cxxflags.gyp')
+
+expect = """\
+Using an optimization flag
+"""
+test.run_built_executable('cxxflags', stdout=expect)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/defines-escaping/defines-escaping.c b/Source/ThirdParty/gyp/test/defines-escaping/defines-escaping.c
new file mode 100644
index 000000000..440757222
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines-escaping/defines-escaping.c
@@ -0,0 +1,11 @@
+/* Copyright (c) 2010 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf(TEST_FORMAT, TEST_ARGS);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/defines-escaping/defines-escaping.gyp b/Source/ThirdParty/gyp/test/defines-escaping/defines-escaping.gyp
new file mode 100644
index 000000000..6f0f3fde4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines-escaping/defines-escaping.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'defines_escaping',
+ 'type': 'executable',
+ 'sources': [
+ 'defines-escaping.c',
+ ],
+ 'defines': [
+ 'TEST_FORMAT="<(test_format)"',
+ 'TEST_ARGS=<(test_args)',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/defines-escaping/gyptest-defines-escaping.py b/Source/ThirdParty/gyp/test/defines-escaping/gyptest-defines-escaping.py
new file mode 100644
index 000000000..69574b3b3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines-escaping/gyptest-defines-escaping.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ define specified by a gyp define using
+various special characters such as quotes, commas, etc.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# Tests string literals, percents, and backslash escapes.
+try:
+ os.environ['GYP_DEFINES'] = (
+ r"""test_format='\n%s\n' """
+ r"""test_args='"Simple test of %s with a literal"'""")
+ test.run_gyp('defines-escaping.gyp')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.build('defines-escaping.gyp')
+
+expect = """
+Simple test of %s with a literal
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test multiple comma-and-space-separated string literals.
+try:
+ os.environ['GYP_DEFINES'] = \
+ r"""test_format='\n%s and %s\n' test_args='"foo", "bar"'"""
+ test.run_gyp('defines-escaping.gyp')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = """
+foo and bar
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test string literals containing quotes.
+try:
+ os.environ['GYP_DEFINES'] = (
+ r"""test_format='\n%s %s %s %s %s\n' """
+ r"""test_args='"\"These,\"","""
+ r""" "\"words,\"","""
+ r""" "\"are,\"","""
+ r""" "\"in,\"","""
+ r""" "\"quotes.\""'""")
+ test.run_gyp('defines-escaping.gyp')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = """
+"These," "words," "are," "in," "quotes."
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test string literals containing single quotes.
+try:
+ os.environ['GYP_DEFINES'] = (
+ r"""test_format='\n%s %s %s %s %s\n' """
+ r"""test_args="\"'These,'\","""
+ r""" \"'words,'\","""
+ r""" \"'are,'\","""
+ r""" \"'in,'\","""
+ r""" \"'quotes.'\"" """)
+ test.run_gyp('defines-escaping.gyp')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = """
+'These,' 'words,' 'are,' 'in,' 'quotes.'
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test string literals containing different numbers of backslashes before quotes
+# (to exercise Windows' quoting behaviour).
+try:
+ os.environ['GYP_DEFINES'] = (
+ r"""test_format='\n%s\n%s\n%s\n' """
+ r"""test_args='"\\\"1 visible slash\\\"","""
+ r""" "\\\\\"2 visible slashes\\\\\"","""
+ r""" "\\\\\\\"3 visible slashes\\\\\\\""'""")
+ test.run_gyp('defines-escaping.gyp')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = r"""
+\"1 visible slash\"
+\\"2 visible slashes\\"
+\\\"3 visible slashes\\\"
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test that various scary sequences are passed unfettered.
+try:
+ os.environ['GYP_DEFINES'] = (
+ r"""test_format='\n%s\n' """
+ r"""test_args='"$foo, &quot; `foo`;"'""")
+ test.run_gyp('defines-escaping.gyp')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = """
+$foo, &quot; `foo`;
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# VisualStudio 2010 can't handle passing %PATH%
+if not (test.format == 'msvs' and test.uses_msbuild):
+ try:
+ os.environ['GYP_DEFINES'] = (
+ """test_format='%s' """
+ """test_args='"%PATH%"'""")
+ test.run_gyp('defines-escaping.gyp')
+ finally:
+ del os.environ['GYP_DEFINES']
+
+ test.sleep()
+ test.touch('defines-escaping.c')
+ test.build('defines-escaping.gyp')
+
+ expect = "%PATH%"
+ test.run_built_executable('defines_escaping', stdout=expect)
+
+
+# Test commas and semi-colons preceded by backslashes (to exercise Windows'
+# quoting behaviour).
+try:
+ os.environ['GYP_DEFINES'] = (
+ r"""test_format='\n%s\n%s\n' """
+ r"""test_args='"\\, \\\\;","""
+ # Same thing again, but enclosed in visible quotes.
+ r""" "\"\\, \\\\;\""'""")
+ test.run_gyp('defines-escaping.gyp')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines-escaping.c')
+test.build('defines-escaping.gyp')
+
+expect = r"""
+\, \\;
+"\, \\;"
+"""
+test.run_built_executable('defines_escaping', stdout=expect)
+
+# We deliberately do not test having an odd number of quotes in a string
+# literal because that isn't feasible in MSVS.
diff --git a/Source/ThirdParty/gyp/test/defines/defines-env.gyp b/Source/ThirdParty/gyp/test/defines/defines-env.gyp
new file mode 100644
index 000000000..1781546ae
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines/defines-env.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'value%': '5',
+ },
+ 'targets': [
+ {
+ 'target_name': 'defines',
+ 'type': 'executable',
+ 'sources': [
+ 'defines.c',
+ ],
+ 'defines': [
+ 'VALUE=<(value)',
+ ],
+ },
+ ],
+}
+
diff --git a/Source/ThirdParty/gyp/test/defines/defines.c b/Source/ThirdParty/gyp/test/defines/defines.c
new file mode 100644
index 000000000..33657ac2c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines/defines.c
@@ -0,0 +1,14 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+#ifdef FOO
+ printf("FOO is defined\n");
+#endif
+ printf("VALUE is %d\n", VALUE);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/defines/defines.gyp b/Source/ThirdParty/gyp/test/defines/defines.gyp
new file mode 100644
index 000000000..3db66e54c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines/defines.gyp
@@ -0,0 +1,36 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'defines',
+ 'type': 'executable',
+ 'sources': [
+ 'defines.c',
+ ],
+ 'defines': [
+ 'FOO',
+ 'VALUE=1',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="fakeos"', {
+ 'targets': [
+ {
+ 'target_name': 'fakeosprogram',
+ 'type': 'executable',
+ 'sources': [
+ 'defines.c',
+ ],
+ 'defines': [
+ 'FOO',
+ 'VALUE=1',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/defines/gyptest-define-override.py b/Source/ThirdParty/gyp/test/defines/gyptest-define-override.py
new file mode 100644
index 000000000..82e325af2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines/gyptest-define-override.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a default gyp define can be overridden.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# Command-line define
+test.run_gyp('defines.gyp', '-D', 'OS=fakeos')
+test.build('defines.gyp')
+test.built_file_must_exist('fakeosprogram', type=test.EXECUTABLE)
+# Clean up the exe so subsequent tests don't find an old exe.
+os.remove(test.built_file_path('fakeosprogram', type=test.EXECUTABLE))
+
+# Without "OS" override, fokeosprogram shouldn't be built.
+test.run_gyp('defines.gyp')
+test.build('defines.gyp')
+test.built_file_must_not_exist('fakeosprogram', type=test.EXECUTABLE)
+
+# Environment define
+os.environ['GYP_DEFINES'] = 'OS=fakeos'
+test.run_gyp('defines.gyp')
+test.build('defines.gyp')
+test.built_file_must_exist('fakeosprogram', type=test.EXECUTABLE)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/defines/gyptest-defines-env-regyp.py b/Source/ThirdParty/gyp/test/defines/gyptest-defines-env-regyp.py
new file mode 100644
index 000000000..70c9ba780
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines/gyptest-defines-env-regyp.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ define specified by a gyp define, and
+the use of the environment during regeneration when the gyp file changes.
+"""
+
+import os
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+try:
+ os.environ['GYP_DEFINES'] = 'value=50'
+ test.run_gyp('defines.gyp')
+finally:
+ # We clear the environ after calling gyp. When the auto-regeneration happens,
+ # the same define should be reused anyway. Reset to empty string first in
+ # case the platform doesn't support unsetenv.
+ os.environ['GYP_DEFINES'] = ''
+ del os.environ['GYP_DEFINES']
+
+test.build('defines.gyp')
+
+expect = """\
+FOO is defined
+VALUE is 1
+"""
+test.run_built_executable('defines', stdout=expect)
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+test.write('defines.gyp', test.read('defines-env.gyp'))
+
+test.build('defines.gyp', test.ALL)
+
+expect = """\
+VALUE is 50
+"""
+test.run_built_executable('defines', stdout=expect)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/defines/gyptest-defines-env.py b/Source/ThirdParty/gyp/test/defines/gyptest-defines-env.py
new file mode 100644
index 000000000..6b4e7175a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines/gyptest-defines-env.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ define specified by a gyp define.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# With the value only given in environment, it should be used.
+try:
+ os.environ['GYP_DEFINES'] = 'value=10'
+ test.run_gyp('defines-env.gyp')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.build('defines-env.gyp')
+
+expect = """\
+VALUE is 10
+"""
+test.run_built_executable('defines', stdout=expect)
+
+
+# With the value given in both command line and environment,
+# command line should take precedence.
+try:
+ os.environ['GYP_DEFINES'] = 'value=20'
+ test.run_gyp('defines-env.gyp', '-Dvalue=25')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines.c')
+test.build('defines-env.gyp')
+
+expect = """\
+VALUE is 25
+"""
+test.run_built_executable('defines', stdout=expect)
+
+
+# With the value only given in environment, it should be ignored if
+# --ignore-environment is specified.
+try:
+ os.environ['GYP_DEFINES'] = 'value=30'
+ test.run_gyp('defines-env.gyp', '--ignore-environment')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines.c')
+test.build('defines-env.gyp')
+
+expect = """\
+VALUE is 5
+"""
+test.run_built_executable('defines', stdout=expect)
+
+
+# With the value given in both command line and environment, and
+# --ignore-environment also specified, command line should still be used.
+try:
+ os.environ['GYP_DEFINES'] = 'value=40'
+ test.run_gyp('defines-env.gyp', '--ignore-environment', '-Dvalue=45')
+finally:
+ del os.environ['GYP_DEFINES']
+
+test.sleep()
+test.touch('defines.c')
+test.build('defines-env.gyp')
+
+expect = """\
+VALUE is 45
+"""
+test.run_built_executable('defines', stdout=expect)
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/defines/gyptest-defines.py b/Source/ThirdParty/gyp/test/defines/gyptest-defines.py
new file mode 100644
index 000000000..a21a6176f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/defines/gyptest-defines.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies build of an executable with C++ defines.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('defines.gyp')
+
+test.build('defines.gyp')
+
+expect = """\
+FOO is defined
+VALUE is 1
+"""
+test.run_built_executable('defines', stdout=expect)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/dependencies/a.c b/Source/ThirdParty/gyp/test/dependencies/a.c
new file mode 100755
index 000000000..3bba111d2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/a.c
@@ -0,0 +1,9 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+extern int funcB();
+
+int funcA() {
+ return funcB();
+}
diff --git a/Source/ThirdParty/gyp/test/dependencies/b/b.c b/Source/ThirdParty/gyp/test/dependencies/b/b.c
new file mode 100755
index 000000000..b5e771bcc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/b/b.c
@@ -0,0 +1,3 @@
+int funcB() {
+ return 2;
+}
diff --git a/Source/ThirdParty/gyp/test/dependencies/b/b.gyp b/Source/ThirdParty/gyp/test/dependencies/b/b.gyp
new file mode 100755
index 000000000..f09e1ff13
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/b/b.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'b',
+ 'type': 'static_library',
+ 'sources': [
+ 'b.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/dependencies/c/c.c b/Source/ThirdParty/gyp/test/dependencies/c/c.c
new file mode 100644
index 000000000..4949daf3e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/c/c.c
@@ -0,0 +1,4 @@
+int funcC() {
+ return 3
+ // Intentional syntax error. This file should never be compiled, so this
+ // shouldn't be a problem.
diff --git a/Source/ThirdParty/gyp/test/dependencies/c/c.gyp b/Source/ThirdParty/gyp/test/dependencies/c/c.gyp
new file mode 100644
index 000000000..eabebea9e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/c/c.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'c_unused',
+ 'type': 'static_library',
+ 'sources': [
+ 'c.c',
+ ],
+ },
+ {
+ 'target_name': 'd',
+ 'type': 'static_library',
+ 'sources': [
+ 'd.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/dependencies/c/d.c b/Source/ThirdParty/gyp/test/dependencies/c/d.c
new file mode 100644
index 000000000..05465fc1a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/c/d.c
@@ -0,0 +1,3 @@
+int funcD() {
+ return 4;
+}
diff --git a/Source/ThirdParty/gyp/test/dependencies/extra_targets.gyp b/Source/ThirdParty/gyp/test/dependencies/extra_targets.gyp
new file mode 100644
index 000000000..c1a26de42
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/extra_targets.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'a',
+ 'type': 'static_library',
+ 'sources': [
+ 'a.c',
+ ],
+ # This only depends on the "d" target; other targets in c.gyp
+ # should not become part of the build (unlike with 'c/c.gyp:*').
+ 'dependencies': ['c/c.gyp:d'],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/dependencies/gyptest-extra-targets.py b/Source/ThirdParty/gyp/test/dependencies/gyptest-extra-targets.py
new file mode 100644
index 000000000..3752f7445
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/gyptest-extra-targets.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that dependencies don't pull unused targets into the build.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('extra_targets.gyp')
+
+# This should fail if it tries to build 'c_unused' since 'c/c.c' has a syntax
+# error and won't compile.
+test.build('extra_targets.gyp', test.ALL)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/dependencies/gyptest-lib-only.py b/Source/ThirdParty/gyp/test/dependencies/gyptest-lib-only.py
new file mode 100755
index 000000000..d90d88fe8
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/gyptest-lib-only.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify that a link time only dependency will get pulled into the set of built
+targets, even if no executable uses it.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('lib_only.gyp')
+
+test.build('lib_only.gyp', test.ALL)
+
+# Make doesn't put static libs in a common 'lib' directory, like it does with
+# shared libs, so check in the obj path corresponding to the source path.
+test.built_file_must_exist('a', type=test.STATIC_LIB, libdir='obj.target')
+
+# TODO(bradnelson/mark):
+# On linux and windows a library target will at least pull its link dependencies
+# into the generated sln/_main.scons, since not doing so confuses users.
+# This is not currently implemented on mac, which has the opposite behavior.
+if test.format == 'xcode':
+ test.built_file_must_not_exist('b', type=test.STATIC_LIB)
+else:
+ test.built_file_must_exist('b', type=test.STATIC_LIB, libdir='obj.target/b')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/dependencies/lib_only.gyp b/Source/ThirdParty/gyp/test/dependencies/lib_only.gyp
new file mode 100755
index 000000000..f6c84dea6
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependencies/lib_only.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'a',
+ 'type': 'static_library',
+ 'sources': [
+ 'a.c',
+ ],
+ 'dependencies': ['b/b.gyp:b'],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/dependency-copy/gyptest-copy.py b/Source/ThirdParty/gyp/test/dependency-copy/gyptest-copy.py
new file mode 100644
index 000000000..5ba7c73d4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependency-copy/gyptest-copy.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies dependencies do the copy step.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('copies.gyp', chdir='src')
+
+test.build('copies.gyp', 'proj2', chdir='src')
+
+test.run_built_executable('proj1',
+ chdir='src',
+ stdout="Hello from file1.c\n")
+test.run_built_executable('proj2',
+ chdir='src',
+ stdout="Hello from file2.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/dependency-copy/src/copies.gyp b/Source/ThirdParty/gyp/test/dependency-copy/src/copies.gyp
new file mode 100644
index 000000000..4176b1878
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependency-copy/src/copies.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'proj1',
+ 'type': 'executable',
+ 'sources': [
+ 'file1.c',
+ ],
+ },
+ {
+ 'target_name': 'proj2',
+ 'type': 'executable',
+ 'sources': [
+ 'file2.c',
+ ],
+ 'dependencies': [
+ 'proj1',
+ ]
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/dependency-copy/src/file1.c b/Source/ThirdParty/gyp/test/dependency-copy/src/file1.c
new file mode 100644
index 000000000..3caf5d634
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependency-copy/src/file1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from file1.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/dependency-copy/src/file2.c b/Source/ThirdParty/gyp/test/dependency-copy/src/file2.c
new file mode 100644
index 000000000..ed45cc012
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/dependency-copy/src/file2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from file2.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/exclusion/exclusion.gyp b/Source/ThirdParty/gyp/test/exclusion/exclusion.gyp
new file mode 100644
index 000000000..1232dabae
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/exclusion/exclusion.gyp
@@ -0,0 +1,23 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'hello',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ 'bogus.c',
+ 'also/not/real.c',
+ 'also/not/real2.c',
+ ],
+ 'sources!': [
+ 'bogus.c',
+ 'also/not/real.c',
+ 'also/not/real2.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/exclusion/gyptest-exclusion.py b/Source/ThirdParty/gyp/test/exclusion/gyptest-exclusion.py
new file mode 100644
index 000000000..1fc32bf87
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/exclusion/gyptest-exclusion.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that exclusions (e.g. sources!) are respected. Excluded sources
+that do not exist should not prevent the build from succeeding.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('exclusion.gyp')
+test.build('exclusion.gyp')
+
+# executables
+test.built_file_must_exist('hello' + test._exe, test.EXECUTABLE, bare=True)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/exclusion/hello.c b/Source/ThirdParty/gyp/test/exclusion/hello.c
new file mode 100644
index 000000000..30e8d5416
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/exclusion/hello.c
@@ -0,0 +1,15 @@
+/* Copyright (c) 2010 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int func1(void) {
+ return 42;
+}
+
+int main(int argc, char *argv[]) {
+ printf("Hello, world!\n");
+ printf("%d\n", func1());
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/actions.gyp b/Source/ThirdParty/gyp/test/generator-output/actions/actions.gyp
new file mode 100644
index 000000000..dded59aff
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/actions.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'pull_in_all_actions',
+ 'type': 'none',
+ 'dependencies': [
+ 'subdir1/executable.gyp:*',
+ 'subdir2/none.gyp:*',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/actions-out/README.txt b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/actions-out/README.txt
new file mode 100644
index 000000000..1b052c9a2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/actions-out/README.txt
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/executable.gyp b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/executable.gyp
new file mode 100644
index 000000000..6bdd60a1f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/executable.gyp
@@ -0,0 +1,44 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'program.c',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'make-prog1',
+ 'inputs': [
+ 'make-prog1.py',
+ ],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/prog1.c',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ {
+ 'action_name': 'make-prog2',
+ 'inputs': [
+ 'make-prog2.py',
+ ],
+ 'outputs': [
+ 'actions-out/prog2.c',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/make-prog1.py b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/make-prog1.py
new file mode 100644
index 000000000..7ea1d8a2d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/make-prog1.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = r"""
+#include <stdio.h>
+
+void prog1(void)
+{
+ printf("Hello from make-prog1.py\n");
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/make-prog2.py b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/make-prog2.py
new file mode 100644
index 000000000..0bfe4973c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/make-prog2.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = r"""
+#include <stdio.h>
+
+void prog2(void)
+{
+ printf("Hello from make-prog2.py\n");
+}
+"""
+
+open(sys.argv[1], 'w').write(contents)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/program.c b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/program.c
new file mode 100644
index 000000000..d5f661d90
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/subdir1/program.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern void prog1(void);
+extern void prog2(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from program.c\n");
+ prog1();
+ prog2();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/actions-out/README.txt b/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/actions-out/README.txt
new file mode 100644
index 000000000..1b052c9a2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/actions-out/README.txt
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/make-file.py b/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/make-file.py
new file mode 100644
index 000000000..fff065314
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/make-file.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = "Hello from make-file.py\n"
+
+open(sys.argv[1], 'wb').write(contents)
diff --git a/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/none.gyp b/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/none.gyp
new file mode 100644
index 000000000..f98f52753
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/actions/subdir2/none.gyp
@@ -0,0 +1,31 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'file',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'actions': [
+ {
+ 'action_name': 'make-file',
+ 'inputs': [
+ 'make-file.py',
+ ],
+ 'outputs': [
+ 'actions-out/file.out',
+ # TODO: enhance testing infrastructure to test this
+ # without having to hard-code the intermediate dir paths.
+ #'<(INTERMEDIATE_DIR)/file.out',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ }
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/copies/copies-out/README.txt b/Source/ThirdParty/gyp/test/generator-output/copies/copies-out/README.txt
new file mode 100644
index 000000000..90ef88619
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/copies/copies-out/README.txt
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/Source/ThirdParty/gyp/test/generator-output/copies/copies.gyp b/Source/ThirdParty/gyp/test/generator-output/copies/copies.gyp
new file mode 100644
index 000000000..479a3d9b6
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/copies/copies.gyp
@@ -0,0 +1,50 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'pull_in_subdir',
+ 'type': 'none',
+ 'dependencies': [
+ 'subdir/subdir.gyp:*',
+ ],
+ },
+ {
+ 'target_name': 'copies1',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': 'copies-out',
+ 'files': [
+ 'file1',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'copies2',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-out',
+ 'files': [
+ 'file2',
+ ],
+ },
+ ],
+ },
+ # Verify that a null 'files' list doesn't gag the generators.
+ {
+ 'target_name': 'copies_null',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-null',
+ 'files': [],
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/copies/file1 b/Source/ThirdParty/gyp/test/generator-output/copies/file1
new file mode 100644
index 000000000..84d55c575
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/copies/file1
@@ -0,0 +1 @@
+file1 contents
diff --git a/Source/ThirdParty/gyp/test/generator-output/copies/file2 b/Source/ThirdParty/gyp/test/generator-output/copies/file2
new file mode 100644
index 000000000..af1b8ae35
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/copies/file2
@@ -0,0 +1 @@
+file2 contents
diff --git a/Source/ThirdParty/gyp/test/generator-output/copies/subdir/copies-out/README.txt b/Source/ThirdParty/gyp/test/generator-output/copies/subdir/copies-out/README.txt
new file mode 100644
index 000000000..90ef88619
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/copies/subdir/copies-out/README.txt
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/Source/ThirdParty/gyp/test/generator-output/copies/subdir/file3 b/Source/ThirdParty/gyp/test/generator-output/copies/subdir/file3
new file mode 100644
index 000000000..43f16f352
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/copies/subdir/file3
@@ -0,0 +1 @@
+file3 contents
diff --git a/Source/ThirdParty/gyp/test/generator-output/copies/subdir/file4 b/Source/ThirdParty/gyp/test/generator-output/copies/subdir/file4
new file mode 100644
index 000000000..5f7270a08
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/copies/subdir/file4
@@ -0,0 +1 @@
+file4 contents
diff --git a/Source/ThirdParty/gyp/test/generator-output/copies/subdir/subdir.gyp b/Source/ThirdParty/gyp/test/generator-output/copies/subdir/subdir.gyp
new file mode 100644
index 000000000..af031d283
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/copies/subdir/subdir.gyp
@@ -0,0 +1,32 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'copies3',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': 'copies-out',
+ 'files': [
+ 'file3',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'copies4',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'destination': '<(PRODUCT_DIR)/copies-out',
+ 'files': [
+ 'file4',
+ ],
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/gyptest-actions.py b/Source/ThirdParty/gyp/test/generator-output/gyptest-actions.py
new file mode 100644
index 000000000..73ac5ae96
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/gyptest-actions.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies --generator-output= behavior when using actions.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# All the generated files should go under 'gypfiles'. The source directory
+# ('actions') should be untouched.
+test.writable(test.workpath('actions'), False)
+test.run_gyp('actions.gyp',
+ '--generator-output=' + test.workpath('gypfiles'),
+ chdir='actions')
+
+test.writable(test.workpath('actions'), True)
+
+test.relocate('actions', 'relocate/actions')
+test.relocate('gypfiles', 'relocate/gypfiles')
+
+test.writable(test.workpath('relocate/actions'), False)
+
+# Some of the action outputs use "pure" relative paths (i.e. without prefixes
+# like <(INTERMEDIATE_DIR) or <(PROGRAM_DIR)). Even though we are building under
+# 'gypfiles', such outputs will still be created relative to the original .gyp
+# sources. Projects probably wouldn't normally do this, since it kind of defeats
+# the purpose of '--generator-output', but it is supported behaviour.
+test.writable(test.workpath('relocate/actions/build'), True)
+test.writable(test.workpath('relocate/actions/subdir1/build'), True)
+test.writable(test.workpath('relocate/actions/subdir1/actions-out'), True)
+test.writable(test.workpath('relocate/actions/subdir2/build'), True)
+test.writable(test.workpath('relocate/actions/subdir2/actions-out'), True)
+
+test.build('actions.gyp', test.ALL, chdir='relocate/gypfiles')
+
+expect = """\
+Hello from program.c
+Hello from make-prog1.py
+Hello from make-prog2.py
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/actions/subdir1'
+else:
+ chdir = 'relocate/gypfiles'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+test.must_match('relocate/actions/subdir2/actions-out/file.out',
+ "Hello from make-file.py\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/generator-output/gyptest-copies.py b/Source/ThirdParty/gyp/test/generator-output/gyptest-copies.py
new file mode 100644
index 000000000..414b7c371
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/gyptest-copies.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies file copies using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.writable(test.workpath('copies'), False)
+
+test.run_gyp('copies.gyp',
+ '--generator-output=' + test.workpath('gypfiles'),
+ chdir='copies')
+
+test.writable(test.workpath('copies'), True)
+
+test.relocate('copies', 'relocate/copies')
+test.relocate('gypfiles', 'relocate/gypfiles')
+
+test.writable(test.workpath('relocate/copies'), False)
+
+test.writable(test.workpath('relocate/copies/build'), True)
+test.writable(test.workpath('relocate/copies/copies-out'), True)
+test.writable(test.workpath('relocate/copies/subdir/build'), True)
+test.writable(test.workpath('relocate/copies/subdir/copies-out'), True)
+
+test.build('copies.gyp', test.ALL, chdir='relocate/gypfiles')
+
+test.must_match(['relocate', 'copies', 'copies-out', 'file1'],
+ "file1 contents\n")
+
+if test.format == 'xcode':
+ chdir = 'relocate/copies/build'
+elif test.format == 'make':
+ chdir = 'relocate/gypfiles/out'
+else:
+ chdir = 'relocate/gypfiles'
+test.must_match([chdir, 'Default', 'copies-out', 'file2'], "file2 contents\n")
+
+test.must_match(['relocate', 'copies', 'subdir', 'copies-out', 'file3'],
+ "file3 contents\n")
+
+if test.format == 'xcode':
+ chdir = 'relocate/copies/subdir/build'
+elif test.format == 'make':
+ chdir = 'relocate/gypfiles/out'
+else:
+ chdir = 'relocate/gypfiles'
+test.must_match([chdir, 'Default', 'copies-out', 'file4'], "file4 contents\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/generator-output/gyptest-relocate.py b/Source/ThirdParty/gyp/test/generator-output/gyptest-relocate.py
new file mode 100644
index 000000000..dd1c2bd6b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/gyptest-relocate.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a project hierarchy created with the --generator-output=
+option can be built even when it's relocated to a different path.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.writable(test.workpath('src'), False)
+
+test.run_gyp('prog1.gyp',
+ '-Dset_symroot=1',
+ '--generator-output=' + test.workpath('gypfiles'),
+ chdir='src')
+
+test.writable(test.workpath('src'), True)
+
+test.relocate('src', 'relocate/src')
+test.relocate('gypfiles', 'relocate/gypfiles')
+
+test.writable(test.workpath('relocate/src'), False)
+
+test.writable(test.workpath('relocate/src/build'), True)
+test.writable(test.workpath('relocate/src/subdir2/build'), True)
+test.writable(test.workpath('relocate/src/subdir3/build'), True)
+
+test.build('prog1.gyp', test.ALL, chdir='relocate/gypfiles')
+
+chdir = 'relocate/gypfiles'
+
+expect = """\
+Hello from %s
+Hello from inc.h
+Hello from inc1/include1.h
+Hello from inc2/include2.h
+Hello from inc3/include3.h
+Hello from subdir2/deeper/deeper.h
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/src'
+test.run_built_executable('prog1', chdir=chdir, stdout=expect % 'prog1.c')
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir2'
+test.run_built_executable('prog2', chdir=chdir, stdout=expect % 'prog2.c')
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir3'
+test.run_built_executable('prog3', chdir=chdir, stdout=expect % 'prog3.c')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/generator-output/gyptest-rules.py b/Source/ThirdParty/gyp/test/generator-output/gyptest-rules.py
new file mode 100644
index 000000000..05b674ffa
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/gyptest-rules.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies --generator-output= behavior when using rules.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.writable(test.workpath('rules'), False)
+
+test.run_gyp('rules.gyp',
+ '--generator-output=' + test.workpath('gypfiles'),
+ chdir='rules')
+
+test.writable(test.workpath('rules'), True)
+
+test.relocate('rules', 'relocate/rules')
+test.relocate('gypfiles', 'relocate/gypfiles')
+
+test.writable(test.workpath('relocate/rules'), False)
+
+test.writable(test.workpath('relocate/rules/build'), True)
+test.writable(test.workpath('relocate/rules/subdir1/build'), True)
+test.writable(test.workpath('relocate/rules/subdir2/build'), True)
+test.writable(test.workpath('relocate/rules/subdir2/rules-out'), True)
+
+test.build('rules.gyp', test.ALL, chdir='relocate/gypfiles')
+
+expect = """\
+Hello from program.c
+Hello from function1.in1
+Hello from function2.in1
+Hello from define3.in0
+Hello from define4.in0
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/rules/subdir1'
+else:
+ chdir = 'relocate/gypfiles'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+test.must_match('relocate/rules/subdir2/rules-out/file1.out',
+ "Hello from file1.in0\n")
+test.must_match('relocate/rules/subdir2/rules-out/file2.out',
+ "Hello from file2.in0\n")
+test.must_match('relocate/rules/subdir2/rules-out/file3.out',
+ "Hello from file3.in1\n")
+test.must_match('relocate/rules/subdir2/rules-out/file4.out',
+ "Hello from file4.in1\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/generator-output/gyptest-subdir2-deep.py b/Source/ThirdParty/gyp/test/generator-output/gyptest-subdir2-deep.py
new file mode 100644
index 000000000..ea1b472eb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/gyptest-subdir2-deep.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target from a .gyp file a few subdirectories
+deep when the --generator-output= option is used to put the build
+configuration files in a separate directory tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.writable(test.workpath('src'), False)
+
+test.writable(test.workpath('src/subdir2/deeper/build'), True)
+
+test.run_gyp('deeper.gyp',
+ '-Dset_symroot=1',
+ '--generator-output=' + test.workpath('gypfiles'),
+ chdir='src/subdir2/deeper')
+
+test.build('deeper.gyp', test.ALL, chdir='gypfiles')
+
+chdir = 'gypfiles'
+
+if test.format == 'xcode':
+ chdir = 'src/subdir2/deeper'
+test.run_built_executable('deeper',
+ chdir=chdir,
+ stdout="Hello from deeper.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/generator-output/gyptest-top-all.py b/Source/ThirdParty/gyp/test/generator-output/gyptest-top-all.py
new file mode 100644
index 000000000..902ceb279
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/gyptest-top-all.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a project hierarchy created when the --generator-output=
+option is used to put the build configuration files in a separate
+directory tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.writable(test.workpath('src'), False)
+
+test.run_gyp('prog1.gyp',
+ '-Dset_symroot=1',
+ '--generator-output=' + test.workpath('gypfiles'),
+ chdir='src')
+
+test.writable(test.workpath('src/build'), True)
+test.writable(test.workpath('src/subdir2/build'), True)
+test.writable(test.workpath('src/subdir3/build'), True)
+
+test.build('prog1.gyp', test.ALL, chdir='gypfiles')
+
+chdir = 'gypfiles'
+
+expect = """\
+Hello from %s
+Hello from inc.h
+Hello from inc1/include1.h
+Hello from inc2/include2.h
+Hello from inc3/include3.h
+Hello from subdir2/deeper/deeper.h
+"""
+
+if test.format == 'xcode':
+ chdir = 'src'
+test.run_built_executable('prog1', chdir=chdir, stdout=expect % 'prog1.c')
+
+if test.format == 'xcode':
+ chdir = 'src/subdir2'
+test.run_built_executable('prog2', chdir=chdir, stdout=expect % 'prog2.c')
+
+if test.format == 'xcode':
+ chdir = 'src/subdir3'
+test.run_built_executable('prog3', chdir=chdir, stdout=expect % 'prog3.c')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/copy-file.py b/Source/ThirdParty/gyp/test/generator-output/rules/copy-file.py
new file mode 100644
index 000000000..938c336ad
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/copy-file.py
@@ -0,0 +1,12 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+contents = open(sys.argv[1], 'r').read()
+open(sys.argv[2], 'wb').write(contents)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/rules.gyp b/Source/ThirdParty/gyp/test/generator-output/rules/rules.gyp
new file mode 100644
index 000000000..dded59aff
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/rules.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'pull_in_all_actions',
+ 'type': 'none',
+ 'dependencies': [
+ 'subdir1/executable.gyp:*',
+ 'subdir2/none.gyp:*',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/define3.in0 b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/define3.in0
new file mode 100644
index 000000000..cc29c643f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/define3.in0
@@ -0,0 +1 @@
+#define STRING3 "Hello from define3.in0\n"
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/define4.in0 b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/define4.in0
new file mode 100644
index 000000000..c9b0467b3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/define4.in0
@@ -0,0 +1 @@
+#define STRING4 "Hello from define4.in0\n"
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/executable.gyp b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/executable.gyp
new file mode 100644
index 000000000..2fd89a0d5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/executable.gyp
@@ -0,0 +1,59 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'program.c',
+ 'function1.in1',
+ 'function2.in1',
+ 'define3.in0',
+ 'define4.in0',
+ ],
+ 'include_dirs': [
+ '<(INTERMEDIATE_DIR)',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'copy_file_0',
+ 'extension': 'in0',
+ 'inputs': [
+ '../copy-file.py',
+ ],
+ 'outputs': [
+ # TODO: fix SCons and Make to support generated files not
+ # in a variable-named path like <(INTERMEDIATE_DIR)
+ #'<(RULE_INPUT_ROOT).c',
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).h',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 0,
+ },
+ {
+ 'rule_name': 'copy_file_1',
+ 'extension': 'in1',
+ 'inputs': [
+ '../copy-file.py',
+ ],
+ 'outputs': [
+ # TODO: fix SCons and Make to support generated files not
+ # in a variable-named path like <(INTERMEDIATE_DIR)
+ #'<(RULE_INPUT_ROOT).c',
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/function1.in1 b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/function1.in1
new file mode 100644
index 000000000..545e7ca16
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/function1.in1
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void function1(void)
+{
+ printf("Hello from function1.in1\n");
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/function2.in1 b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/function2.in1
new file mode 100644
index 000000000..6bad43f9c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/function2.in1
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void function2(void)
+{
+ printf("Hello from function2.in1\n");
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/program.c b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/program.c
new file mode 100644
index 000000000..27fd31ed4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir1/program.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include "define3.h"
+#include "define4.h"
+
+extern void function1(void);
+extern void function2(void);
+extern void function3(void);
+extern void function4(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from program.c\n");
+ function1();
+ function2();
+ printf("%s", STRING3);
+ printf("%s", STRING4);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file1.in0 b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file1.in0
new file mode 100644
index 000000000..7aca64f4c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file1.in0
@@ -0,0 +1 @@
+Hello from file1.in0
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file2.in0 b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file2.in0
new file mode 100644
index 000000000..80a281a2a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file2.in0
@@ -0,0 +1 @@
+Hello from file2.in0
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file3.in1 b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file3.in1
new file mode 100644
index 000000000..60ae2e793
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file3.in1
@@ -0,0 +1 @@
+Hello from file3.in1
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file4.in1 b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file4.in1
new file mode 100644
index 000000000..5a3c30720
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/file4.in1
@@ -0,0 +1 @@
+Hello from file4.in1
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/none.gyp b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/none.gyp
new file mode 100644
index 000000000..664cbd9cb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/none.gyp
@@ -0,0 +1,49 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'files',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'file1.in0',
+ 'file2.in0',
+ 'file3.in1',
+ 'file4.in1',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'copy_file_0',
+ 'extension': 'in0',
+ 'inputs': [
+ '../copy-file.py',
+ ],
+ 'outputs': [
+ 'rules-out/<(RULE_INPUT_ROOT).out',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 0,
+ },
+ {
+ 'rule_name': 'copy_file_1',
+ 'extension': 'in1',
+ 'inputs': [
+ '../copy-file.py',
+ ],
+ 'outputs': [
+ 'rules-out/<(RULE_INPUT_ROOT).out',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/rules-out/README.txt b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/rules-out/README.txt
new file mode 100644
index 000000000..1b052c9a2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/rules/subdir2/rules-out/README.txt
@@ -0,0 +1,4 @@
+A place-holder for this Xcode build output directory, so that the
+test script can verify that .xcodeproj files are not created in
+their normal location by making the src/ read-only, and then
+selectively making this build directory writable.
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/inc.h b/Source/ThirdParty/gyp/test/generator-output/src/inc.h
new file mode 100644
index 000000000..57aa1a5a7
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/inc.h
@@ -0,0 +1 @@
+#define INC_STRING "inc.h"
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/inc1/include1.h b/Source/ThirdParty/gyp/test/generator-output/src/inc1/include1.h
new file mode 100644
index 000000000..1d59065fc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/inc1/include1.h
@@ -0,0 +1 @@
+#define INCLUDE1_STRING "inc1/include1.h"
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/prog1.c b/Source/ThirdParty/gyp/test/generator-output/src/prog1.c
new file mode 100644
index 000000000..656f81d5f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/prog1.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+#include "include3.h"
+#include "deeper.h"
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog1.c\n");
+ printf("Hello from %s\n", INC_STRING);
+ printf("Hello from %s\n", INCLUDE1_STRING);
+ printf("Hello from %s\n", INCLUDE2_STRING);
+ printf("Hello from %s\n", INCLUDE3_STRING);
+ printf("Hello from %s\n", DEEPER_STRING);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/prog1.gyp b/Source/ThirdParty/gyp/test/generator-output/src/prog1.gyp
new file mode 100644
index 000000000..d50e6fb0a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/prog1.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ 'symroot.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog1',
+ 'type': 'executable',
+ 'dependencies': [
+ 'subdir2/prog2.gyp:prog2',
+ ],
+ 'include_dirs': [
+ '.',
+ 'inc1',
+ 'subdir2/inc2',
+ 'subdir3/inc3',
+ 'subdir2/deeper',
+ ],
+ 'sources': [
+ 'prog1.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.c b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.c
new file mode 100644
index 000000000..56c49d1f7
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from deeper.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp
new file mode 100644
index 000000000..864877087
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../../symroot.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'deeper',
+ 'type': 'executable',
+ 'sources': [
+ 'deeper.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.h b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.h
new file mode 100644
index 000000000..f6484a0fe
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/deeper/deeper.h
@@ -0,0 +1 @@
+#define DEEPER_STRING "subdir2/deeper/deeper.h"
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir2/inc2/include2.h b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/inc2/include2.h
new file mode 100644
index 000000000..1ccfa5dea
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/inc2/include2.h
@@ -0,0 +1 @@
+#define INCLUDE2_STRING "inc2/include2.h"
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir2/prog2.c b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/prog2.c
new file mode 100644
index 000000000..38d6c84d1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/prog2.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+#include "include3.h"
+#include "deeper.h"
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog2.c\n");
+ printf("Hello from %s\n", INC_STRING);
+ printf("Hello from %s\n", INCLUDE1_STRING);
+ printf("Hello from %s\n", INCLUDE2_STRING);
+ printf("Hello from %s\n", INCLUDE3_STRING);
+ printf("Hello from %s\n", DEEPER_STRING);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir2/prog2.gyp b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/prog2.gyp
new file mode 100644
index 000000000..7176ed8be
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir2/prog2.gyp
@@ -0,0 +1,28 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../symroot.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog2',
+ 'type': 'executable',
+ 'include_dirs': [
+ '..',
+ '../inc1',
+ 'inc2',
+ '../subdir3/inc3',
+ 'deeper',
+ ],
+ 'dependencies': [
+ '../subdir3/prog3.gyp:prog3',
+ ],
+ 'sources': [
+ 'prog2.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir3/inc3/include3.h b/Source/ThirdParty/gyp/test/generator-output/src/subdir3/inc3/include3.h
new file mode 100644
index 000000000..bf53bf1f0
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir3/inc3/include3.h
@@ -0,0 +1 @@
+#define INCLUDE3_STRING "inc3/include3.h"
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir3/prog3.c b/Source/ThirdParty/gyp/test/generator-output/src/subdir3/prog3.c
new file mode 100644
index 000000000..7848b45ab
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir3/prog3.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+#include "include3.h"
+#include "deeper.h"
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog3.c\n");
+ printf("Hello from %s\n", INC_STRING);
+ printf("Hello from %s\n", INCLUDE1_STRING);
+ printf("Hello from %s\n", INCLUDE2_STRING);
+ printf("Hello from %s\n", INCLUDE3_STRING);
+ printf("Hello from %s\n", DEEPER_STRING);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/subdir3/prog3.gyp b/Source/ThirdParty/gyp/test/generator-output/src/subdir3/prog3.gyp
new file mode 100644
index 000000000..46c5e000a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/subdir3/prog3.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../symroot.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog3',
+ 'type': 'executable',
+ 'include_dirs': [
+ '..',
+ '../inc1',
+ '../subdir2/inc2',
+ 'inc3',
+ '../subdir2/deeper',
+ ],
+ 'sources': [
+ 'prog3.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/generator-output/src/symroot.gypi b/Source/ThirdParty/gyp/test/generator-output/src/symroot.gypi
new file mode 100644
index 000000000..519916427
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/generator-output/src/symroot.gypi
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'set_symroot%': 0,
+ },
+ 'conditions': [
+ ['set_symroot == 1', {
+ 'xcode_settings': {
+ 'SYMROOT': '<(DEPTH)/build',
+ },
+ }],
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/hello/gyptest-all.py b/Source/ThirdParty/gyp/test/hello/gyptest-all.py
new file mode 100644
index 000000000..9ecff556e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/gyptest-all.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp', test.ALL)
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', test.ALL)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/hello/gyptest-default.py b/Source/ThirdParty/gyp/test/hello/gyptest-default.py
new file mode 100644
index 000000000..76fffb3ea
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/gyptest-default.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp')
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', test.DEFAULT)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/hello/gyptest-disable-regyp.py b/Source/ThirdParty/gyp/test/hello/gyptest-disable-regyp.py
new file mode 100644
index 000000000..1e4b30667
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/gyptest-disable-regyp.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that Makefiles don't get rebuilt when a source gyp file changes and
+the disable_regeneration generator flag is set.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('hello.gyp', '-Gauto_regeneration=0')
+
+test.build('hello.gyp', test.ALL)
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+test.write('hello.gyp', test.read('hello2.gyp'))
+
+test.build('hello.gyp', test.ALL)
+
+# Should still be the old executable, as regeneration was disabled.
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/hello/gyptest-regyp.py b/Source/ThirdParty/gyp/test/hello/gyptest-regyp.py
new file mode 100644
index 000000000..827c7235c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/gyptest-regyp.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that Makefiles get rebuilt when a source gyp file changes.
+"""
+
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp', test.ALL)
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+# Sleep so that the changed gyp file will have a newer timestamp than the
+# previously generated build files.
+test.sleep()
+test.write('hello.gyp', test.read('hello2.gyp'))
+
+test.build('hello.gyp', test.ALL)
+
+test.run_built_executable('hello', stdout="Hello, two!\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/hello/gyptest-target.py b/Source/ThirdParty/gyp/test/hello/gyptest-target.py
new file mode 100755
index 000000000..2f0a2a33d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/gyptest-target.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using an explicit build target of 'hello'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp', 'hello')
+
+test.run_built_executable('hello', stdout="Hello, world!\n")
+
+test.up_to_date('hello.gyp', 'hello')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/hello/hello.c b/Source/ThirdParty/gyp/test/hello/hello.c
new file mode 100644
index 000000000..8dbecc049
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/hello.c
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello, world!\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/hello/hello.gyp b/Source/ThirdParty/gyp/test/hello/hello.gyp
new file mode 100644
index 000000000..1974d51cc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/hello.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'hello',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/hello/hello2.c b/Source/ThirdParty/gyp/test/hello/hello2.c
new file mode 100644
index 000000000..19ef3fbd5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/hello2.c
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello, two!\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/hello/hello2.gyp b/Source/ThirdParty/gyp/test/hello/hello2.gyp
new file mode 100644
index 000000000..25b08caf3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/hello/hello2.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'hello',
+ 'type': 'executable',
+ 'sources': [
+ 'hello2.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py b/Source/ThirdParty/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py
new file mode 100644
index 000000000..a2b9f3018
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/home_dot_gyp/gyptest-home-includes-regyp.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies inclusion of $HOME/.gyp/includes.gypi works properly with relocation
+and with regeneration.
+"""
+
+import os
+import TestGyp
+
+# Regenerating build files when a gyp file changes is currently only supported
+# by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+os.environ['HOME'] = os.path.abspath('home')
+
+test.run_gyp('all.gyp', chdir='src')
+
+# After relocating, we should still be able to build (build file shouldn't
+# contain relative reference to ~/.gyp/includes.gypi)
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+ chdir='relocate/src',
+ stdout="FOO is fromhome\n");
+
+# Building should notice any changes to ~/.gyp/includes.gypi and regyp.
+test.sleep()
+
+test.write('home/.gyp/include.gypi', test.read('home2/.gyp/include.gypi'))
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+ chdir='relocate/src',
+ stdout="FOO is fromhome2\n");
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/home_dot_gyp/gyptest-home-includes.py b/Source/ThirdParty/gyp/test/home_dot_gyp/gyptest-home-includes.py
new file mode 100644
index 000000000..6a0e9651f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/home_dot_gyp/gyptest-home-includes.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies inclusion of $HOME/.gyp/includes.gypi works.
+"""
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+os.environ['HOME'] = os.path.abspath('home')
+
+test.run_gyp('all.gyp', chdir='src')
+
+# After relocating, we should still be able to build (build file shouldn't
+# contain relative reference to ~/.gyp/includes.gypi)
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('printfoo',
+ chdir='relocate/src',
+ stdout="FOO is fromhome\n");
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/home_dot_gyp/home/.gyp/include.gypi b/Source/ThirdParty/gyp/test/home_dot_gyp/home/.gyp/include.gypi
new file mode 100644
index 000000000..fcfb39bef
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/home_dot_gyp/home/.gyp/include.gypi
@@ -0,0 +1,5 @@
+{
+ 'variables': {
+ 'foo': '"fromhome"',
+ },
+}
diff --git a/Source/ThirdParty/gyp/test/home_dot_gyp/home2/.gyp/include.gypi b/Source/ThirdParty/gyp/test/home_dot_gyp/home2/.gyp/include.gypi
new file mode 100644
index 000000000..f0d84b31a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/home_dot_gyp/home2/.gyp/include.gypi
@@ -0,0 +1,5 @@
+{
+ 'variables': {
+ 'foo': '"fromhome2"',
+ },
+}
diff --git a/Source/ThirdParty/gyp/test/home_dot_gyp/src/all.gyp b/Source/ThirdParty/gyp/test/home_dot_gyp/src/all.gyp
new file mode 100644
index 000000000..14b6aea28
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/home_dot_gyp/src/all.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'foo%': '"fromdefault"',
+ },
+ 'targets': [
+ {
+ 'target_name': 'printfoo',
+ 'type': 'executable',
+ 'sources': [
+ 'printfoo.c',
+ ],
+ 'defines': [
+ 'FOO=<(foo)',
+ ],
+ },
+ ],
+}
+
diff --git a/Source/ThirdParty/gyp/test/home_dot_gyp/src/printfoo.c b/Source/ThirdParty/gyp/test/home_dot_gyp/src/printfoo.c
new file mode 100644
index 000000000..92d2cbacb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/home_dot_gyp/src/printfoo.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("FOO is %s\n", FOO);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/include_dirs/gyptest-all.py b/Source/ThirdParty/gyp/test/include_dirs/gyptest-all.py
new file mode 100644
index 000000000..94a1338d4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/gyptest-all.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies use of include_dirs when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'scons':
+ test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n')
+
+test.run_gyp('includes.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('includes.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from includes.c
+Hello from inc.h
+Hello from include1.h
+Hello from subdir/inc2/include2.h
+Hello from shadow2/shadow.h
+"""
+test.run_built_executable('includes', stdout=expect, chdir='relocate/src')
+
+if test.format == 'xcode':
+ chdir='relocate/src/subdir'
+else:
+ chdir='relocate/src'
+
+expect = """\
+Hello from subdir/subdir_includes.c
+Hello from subdir/inc.h
+Hello from include1.h
+Hello from subdir/inc2/include2.h
+"""
+test.run_built_executable('subdir_includes', stdout=expect, chdir=chdir)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/include_dirs/gyptest-default.py b/Source/ThirdParty/gyp/test/include_dirs/gyptest-default.py
new file mode 100644
index 000000000..42acd1f96
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/gyptest-default.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies use of include_dirs when using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+if test.format == 'scons':
+ test.skip_test('TODO: http://code.google.com/p/gyp/issues/detail?id=176\n')
+
+test.run_gyp('includes.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('includes.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from includes.c
+Hello from inc.h
+Hello from include1.h
+Hello from subdir/inc2/include2.h
+Hello from shadow2/shadow.h
+"""
+test.run_built_executable('includes', stdout=expect, chdir='relocate/src')
+
+if test.format == 'xcode':
+ chdir='relocate/src/subdir'
+else:
+ chdir='relocate/src'
+
+expect = """\
+Hello from subdir/subdir_includes.c
+Hello from subdir/inc.h
+Hello from include1.h
+Hello from subdir/inc2/include2.h
+"""
+test.run_built_executable('subdir_includes', stdout=expect, chdir=chdir)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/inc.h b/Source/ThirdParty/gyp/test/include_dirs/src/inc.h
new file mode 100644
index 000000000..0398d6915
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/inc.h
@@ -0,0 +1 @@
+#define INC_STRING "inc.h"
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/inc1/include1.h b/Source/ThirdParty/gyp/test/include_dirs/src/inc1/include1.h
new file mode 100644
index 000000000..43356b5f4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/inc1/include1.h
@@ -0,0 +1 @@
+#define INCLUDE1_STRING "include1.h"
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/includes.c b/Source/ThirdParty/gyp/test/include_dirs/src/includes.c
new file mode 100644
index 000000000..e2afbd3ed
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/includes.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+#include "shadow.h"
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from includes.c\n");
+ printf("Hello from %s\n", INC_STRING);
+ printf("Hello from %s\n", INCLUDE1_STRING);
+ printf("Hello from %s\n", INCLUDE2_STRING);
+ /* Test that include_dirs happen first: The gyp file has a -Ishadow1
+ cflag and an include_dir of shadow2. Including shadow.h should get
+ the shadow.h from the include_dir. */
+ printf("Hello from %s\n", SHADOW_STRING);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/includes.gyp b/Source/ThirdParty/gyp/test/include_dirs/src/includes.gyp
new file mode 100644
index 000000000..359269020
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/includes.gyp
@@ -0,0 +1,27 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'includes',
+ 'type': 'executable',
+ 'dependencies': [
+ 'subdir/subdir_includes.gyp:subdir_includes',
+ ],
+ 'cflags': [
+ '-Ishadow1',
+ ],
+ 'include_dirs': [
+ '.',
+ 'inc1',
+ 'shadow2',
+ 'subdir/inc2',
+ ],
+ 'sources': [
+ 'includes.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/shadow1/shadow.h b/Source/ThirdParty/gyp/test/include_dirs/src/shadow1/shadow.h
new file mode 100644
index 000000000..80f6de20b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/shadow1/shadow.h
@@ -0,0 +1 @@
+#define SHADOW_STRING "shadow1/shadow.h"
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/shadow2/shadow.h b/Source/ThirdParty/gyp/test/include_dirs/src/shadow2/shadow.h
new file mode 100644
index 000000000..fad5ccd08
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/shadow2/shadow.h
@@ -0,0 +1 @@
+#define SHADOW_STRING "shadow2/shadow.h"
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/subdir/inc.h b/Source/ThirdParty/gyp/test/include_dirs/src/subdir/inc.h
new file mode 100644
index 000000000..0a68d7b36
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/subdir/inc.h
@@ -0,0 +1 @@
+#define INC_STRING "subdir/inc.h"
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/subdir/inc2/include2.h b/Source/ThirdParty/gyp/test/include_dirs/src/subdir/inc2/include2.h
new file mode 100644
index 000000000..721577eff
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/subdir/inc2/include2.h
@@ -0,0 +1 @@
+#define INCLUDE2_STRING "subdir/inc2/include2.h"
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/subdir/subdir_includes.c b/Source/ThirdParty/gyp/test/include_dirs/src/subdir/subdir_includes.c
new file mode 100644
index 000000000..727f68220
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/subdir/subdir_includes.c
@@ -0,0 +1,14 @@
+#include <stdio.h>
+
+#include "inc.h"
+#include "include1.h"
+#include "include2.h"
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from subdir/subdir_includes.c\n");
+ printf("Hello from %s\n", INC_STRING);
+ printf("Hello from %s\n", INCLUDE1_STRING);
+ printf("Hello from %s\n", INCLUDE2_STRING);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/include_dirs/src/subdir/subdir_includes.gyp b/Source/ThirdParty/gyp/test/include_dirs/src/subdir/subdir_includes.gyp
new file mode 100644
index 000000000..257d052c3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/include_dirs/src/subdir/subdir_includes.gyp
@@ -0,0 +1,20 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'subdir_includes',
+ 'type': 'executable',
+ 'include_dirs': [
+ '.',
+ '../inc1',
+ 'inc2',
+ ],
+ 'sources': [
+ 'subdir_includes.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/lib/README.txt b/Source/ThirdParty/gyp/test/lib/README.txt
new file mode 100644
index 000000000..b3d724574
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/lib/README.txt
@@ -0,0 +1,17 @@
+Supporting modules for GYP testing.
+
+ TestCmd.py
+ TestCommon.py
+
+ Modules for generic testing of command-line utilities,
+ specifically including the ability to copy a test configuration
+ to temporary directories (with default cleanup on exit) as part
+ of running test scripts that invoke commands, compare actual
+ against expected output, etc.
+
+ Our copies of these come from the SCons project,
+ http://www.scons.org/.
+
+ TestGyp.py
+
+ Modules for GYP-specific tests, of course.
diff --git a/Source/ThirdParty/gyp/test/lib/TestCmd.py b/Source/ThirdParty/gyp/test/lib/TestCmd.py
new file mode 100644
index 000000000..029c1d05f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/lib/TestCmd.py
@@ -0,0 +1,1591 @@
+"""
+TestCmd.py: a testing framework for commands and scripts.
+
+The TestCmd module provides a framework for portable automated testing
+of executable commands and scripts (in any language, not just Python),
+especially commands and scripts that require file system interaction.
+
+In addition to running tests and evaluating conditions, the TestCmd
+module manages and cleans up one or more temporary workspace
+directories, and provides methods for creating files and directories in
+those workspace directories from in-line data, here-documents), allowing
+tests to be completely self-contained.
+
+A TestCmd environment object is created via the usual invocation:
+
+ import TestCmd
+ test = TestCmd.TestCmd()
+
+There are a bunch of keyword arguments available at instantiation:
+
+ test = TestCmd.TestCmd(description = 'string',
+ program = 'program_or_script_to_test',
+ interpreter = 'script_interpreter',
+ workdir = 'prefix',
+ subdir = 'subdir',
+ verbose = Boolean,
+ match = default_match_function,
+ diff = default_diff_function,
+ combine = Boolean)
+
+There are a bunch of methods that let you do different things:
+
+ test.verbose_set(1)
+
+ test.description_set('string')
+
+ test.program_set('program_or_script_to_test')
+
+ test.interpreter_set('script_interpreter')
+ test.interpreter_set(['script_interpreter', 'arg'])
+
+ test.workdir_set('prefix')
+ test.workdir_set('')
+
+ test.workpath('file')
+ test.workpath('subdir', 'file')
+
+ test.subdir('subdir', ...)
+
+ test.rmdir('subdir', ...)
+
+ test.write('file', "contents\n")
+ test.write(['subdir', 'file'], "contents\n")
+
+ test.read('file')
+ test.read(['subdir', 'file'])
+ test.read('file', mode)
+ test.read(['subdir', 'file'], mode)
+
+ test.writable('dir', 1)
+ test.writable('dir', None)
+
+ test.preserve(condition, ...)
+
+ test.cleanup(condition)
+
+ test.command_args(program = 'program_or_script_to_run',
+ interpreter = 'script_interpreter',
+ arguments = 'arguments to pass to program')
+
+ test.run(program = 'program_or_script_to_run',
+ interpreter = 'script_interpreter',
+ arguments = 'arguments to pass to program',
+ chdir = 'directory_to_chdir_to',
+ stdin = 'input to feed to the program\n')
+ universal_newlines = True)
+
+ p = test.start(program = 'program_or_script_to_run',
+ interpreter = 'script_interpreter',
+ arguments = 'arguments to pass to program',
+ universal_newlines = None)
+
+ test.finish(self, p)
+
+ test.pass_test()
+ test.pass_test(condition)
+ test.pass_test(condition, function)
+
+ test.fail_test()
+ test.fail_test(condition)
+ test.fail_test(condition, function)
+ test.fail_test(condition, function, skip)
+
+ test.no_result()
+ test.no_result(condition)
+ test.no_result(condition, function)
+ test.no_result(condition, function, skip)
+
+ test.stdout()
+ test.stdout(run)
+
+ test.stderr()
+ test.stderr(run)
+
+ test.symlink(target, link)
+
+ test.banner(string)
+ test.banner(string, width)
+
+ test.diff(actual, expected)
+
+ test.match(actual, expected)
+
+ test.match_exact("actual 1\nactual 2\n", "expected 1\nexpected 2\n")
+ test.match_exact(["actual 1\n", "actual 2\n"],
+ ["expected 1\n", "expected 2\n"])
+
+ test.match_re("actual 1\nactual 2\n", regex_string)
+ test.match_re(["actual 1\n", "actual 2\n"], list_of_regexes)
+
+ test.match_re_dotall("actual 1\nactual 2\n", regex_string)
+ test.match_re_dotall(["actual 1\n", "actual 2\n"], list_of_regexes)
+
+ test.tempdir()
+ test.tempdir('temporary-directory')
+
+ test.sleep()
+ test.sleep(seconds)
+
+ test.where_is('foo')
+ test.where_is('foo', 'PATH1:PATH2')
+ test.where_is('foo', 'PATH1;PATH2', '.suffix3;.suffix4')
+
+ test.unlink('file')
+ test.unlink('subdir', 'file')
+
+The TestCmd module provides pass_test(), fail_test(), and no_result()
+unbound functions that report test results for use with the Aegis change
+management system. These methods terminate the test immediately,
+reporting PASSED, FAILED, or NO RESULT respectively, and exiting with
+status 0 (success), 1 or 2 respectively. This allows for a distinction
+between an actual failed test and a test that could not be properly
+evaluated because of an external condition (such as a full file system
+or incorrect permissions).
+
+ import TestCmd
+
+ TestCmd.pass_test()
+ TestCmd.pass_test(condition)
+ TestCmd.pass_test(condition, function)
+
+ TestCmd.fail_test()
+ TestCmd.fail_test(condition)
+ TestCmd.fail_test(condition, function)
+ TestCmd.fail_test(condition, function, skip)
+
+ TestCmd.no_result()
+ TestCmd.no_result(condition)
+ TestCmd.no_result(condition, function)
+ TestCmd.no_result(condition, function, skip)
+
+The TestCmd module also provides unbound functions that handle matching
+in the same way as the match_*() methods described above.
+
+ import TestCmd
+
+ test = TestCmd.TestCmd(match = TestCmd.match_exact)
+
+ test = TestCmd.TestCmd(match = TestCmd.match_re)
+
+ test = TestCmd.TestCmd(match = TestCmd.match_re_dotall)
+
+The TestCmd module provides unbound functions that can be used for the
+"diff" argument to TestCmd.TestCmd instantiation:
+
+ import TestCmd
+
+ test = TestCmd.TestCmd(match = TestCmd.match_re,
+ diff = TestCmd.diff_re)
+
+ test = TestCmd.TestCmd(diff = TestCmd.simple_diff)
+
+The "diff" argument can also be used with standard difflib functions:
+
+ import difflib
+
+ test = TestCmd.TestCmd(diff = difflib.context_diff)
+
+ test = TestCmd.TestCmd(diff = difflib.unified_diff)
+
+Lastly, the where_is() method also exists in an unbound function
+version.
+
+ import TestCmd
+
+ TestCmd.where_is('foo')
+ TestCmd.where_is('foo', 'PATH1:PATH2')
+ TestCmd.where_is('foo', 'PATH1;PATH2', '.suffix3;.suffix4')
+"""
+
+# Copyright 2000-2010 Steven Knight
+# This module is free software, and you may redistribute it and/or modify
+# it under the same terms as Python itself, so long as this copyright message
+# and disclaimer are retained in their original form.
+#
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
+# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+__author__ = "Steven Knight <knight at baldmt dot com>"
+__revision__ = "TestCmd.py 0.37.D001 2010/01/11 16:55:50 knight"
+__version__ = "0.37"
+
+import errno
+import os
+import os.path
+import re
+import shutil
+import stat
+import string
+import sys
+import tempfile
+import time
+import traceback
+import types
+import UserList
+
+__all__ = [
+ 'diff_re',
+ 'fail_test',
+ 'no_result',
+ 'pass_test',
+ 'match_exact',
+ 'match_re',
+ 'match_re_dotall',
+ 'python_executable',
+ 'TestCmd'
+]
+
+try:
+ import difflib
+except ImportError:
+ __all__.append('simple_diff')
+
+def is_List(e):
+ return type(e) is types.ListType \
+ or isinstance(e, UserList.UserList)
+
+try:
+ from UserString import UserString
+except ImportError:
+ class UserString:
+ pass
+
+if hasattr(types, 'UnicodeType'):
+ def is_String(e):
+ return type(e) is types.StringType \
+ or type(e) is types.UnicodeType \
+ or isinstance(e, UserString)
+else:
+ def is_String(e):
+ return type(e) is types.StringType or isinstance(e, UserString)
+
+tempfile.template = 'testcmd.'
+if os.name in ('posix', 'nt'):
+ tempfile.template = 'testcmd.' + str(os.getpid()) + '.'
+else:
+ tempfile.template = 'testcmd.'
+
+re_space = re.compile('\s')
+
+_Cleanup = []
+
+_chain_to_exitfunc = None
+
+def _clean():
+ global _Cleanup
+ cleanlist = filter(None, _Cleanup)
+ del _Cleanup[:]
+ cleanlist.reverse()
+ for test in cleanlist:
+ test.cleanup()
+ if _chain_to_exitfunc:
+ _chain_to_exitfunc()
+
+try:
+ import atexit
+except ImportError:
+ # TODO(1.5): atexit requires python 2.0, so chain sys.exitfunc
+ try:
+ _chain_to_exitfunc = sys.exitfunc
+ except AttributeError:
+ pass
+ sys.exitfunc = _clean
+else:
+ atexit.register(_clean)
+
+try:
+ zip
+except NameError:
+ def zip(*lists):
+ result = []
+ for i in xrange(min(map(len, lists))):
+ result.append(tuple(map(lambda l, i=i: l[i], lists)))
+ return result
+
+class Collector:
+ def __init__(self, top):
+ self.entries = [top]
+ def __call__(self, arg, dirname, names):
+ pathjoin = lambda n, d=dirname: os.path.join(d, n)
+ self.entries.extend(map(pathjoin, names))
+
+def _caller(tblist, skip):
+ string = ""
+ arr = []
+ for file, line, name, text in tblist:
+ if file[-10:] == "TestCmd.py":
+ break
+ arr = [(file, line, name, text)] + arr
+ atfrom = "at"
+ for file, line, name, text in arr[skip:]:
+ if name in ("?", "<module>"):
+ name = ""
+ else:
+ name = " (" + name + ")"
+ string = string + ("%s line %d of %s%s\n" % (atfrom, line, file, name))
+ atfrom = "\tfrom"
+ return string
+
+def fail_test(self = None, condition = 1, function = None, skip = 0):
+ """Cause the test to fail.
+
+ By default, the fail_test() method reports that the test FAILED
+ and exits with a status of 1. If a condition argument is supplied,
+ the test fails only if the condition is true.
+ """
+ if not condition:
+ return
+ if not function is None:
+ function()
+ of = ""
+ desc = ""
+ sep = " "
+ if not self is None:
+ if self.program:
+ of = " of " + self.program
+ sep = "\n\t"
+ if self.description:
+ desc = " [" + self.description + "]"
+ sep = "\n\t"
+
+ at = _caller(traceback.extract_stack(), skip)
+ sys.stderr.write("FAILED test" + of + desc + sep + at)
+
+ sys.exit(1)
+
+def no_result(self = None, condition = 1, function = None, skip = 0):
+ """Causes a test to exit with no valid result.
+
+ By default, the no_result() method reports NO RESULT for the test
+ and exits with a status of 2. If a condition argument is supplied,
+ the test fails only if the condition is true.
+ """
+ if not condition:
+ return
+ if not function is None:
+ function()
+ of = ""
+ desc = ""
+ sep = " "
+ if not self is None:
+ if self.program:
+ of = " of " + self.program
+ sep = "\n\t"
+ if self.description:
+ desc = " [" + self.description + "]"
+ sep = "\n\t"
+
+ at = _caller(traceback.extract_stack(), skip)
+ sys.stderr.write("NO RESULT for test" + of + desc + sep + at)
+
+ sys.exit(2)
+
+def pass_test(self = None, condition = 1, function = None):
+ """Causes a test to pass.
+
+ By default, the pass_test() method reports PASSED for the test
+ and exits with a status of 0. If a condition argument is supplied,
+ the test passes only if the condition is true.
+ """
+ if not condition:
+ return
+ if not function is None:
+ function()
+ sys.stderr.write("PASSED\n")
+ sys.exit(0)
+
+def match_exact(lines = None, matches = None):
+ """
+ """
+ if not is_List(lines):
+ lines = string.split(lines, "\n")
+ if not is_List(matches):
+ matches = string.split(matches, "\n")
+ if len(lines) != len(matches):
+ return
+ for i in range(len(lines)):
+ if lines[i] != matches[i]:
+ return
+ return 1
+
+def match_re(lines = None, res = None):
+ """
+ """
+ if not is_List(lines):
+ lines = string.split(lines, "\n")
+ if not is_List(res):
+ res = string.split(res, "\n")
+ if len(lines) != len(res):
+ return
+ for i in range(len(lines)):
+ s = "^" + res[i] + "$"
+ try:
+ expr = re.compile(s)
+ except re.error, e:
+ msg = "Regular expression error in %s: %s"
+ raise re.error, msg % (repr(s), e[0])
+ if not expr.search(lines[i]):
+ return
+ return 1
+
+def match_re_dotall(lines = None, res = None):
+ """
+ """
+ if not type(lines) is type(""):
+ lines = string.join(lines, "\n")
+ if not type(res) is type(""):
+ res = string.join(res, "\n")
+ s = "^" + res + "$"
+ try:
+ expr = re.compile(s, re.DOTALL)
+ except re.error, e:
+ msg = "Regular expression error in %s: %s"
+ raise re.error, msg % (repr(s), e[0])
+ if expr.match(lines):
+ return 1
+
+try:
+ import difflib
+except ImportError:
+ pass
+else:
+ def simple_diff(a, b, fromfile='', tofile='',
+ fromfiledate='', tofiledate='', n=3, lineterm='\n'):
+ """
+ A function with the same calling signature as difflib.context_diff
+ (diff -c) and difflib.unified_diff (diff -u) but which prints
+ output like the simple, unadorned 'diff" command.
+ """
+ sm = difflib.SequenceMatcher(None, a, b)
+ def comma(x1, x2):
+ return x1+1 == x2 and str(x2) or '%s,%s' % (x1+1, x2)
+ result = []
+ for op, a1, a2, b1, b2 in sm.get_opcodes():
+ if op == 'delete':
+ result.append("%sd%d" % (comma(a1, a2), b1))
+ result.extend(map(lambda l: '< ' + l, a[a1:a2]))
+ elif op == 'insert':
+ result.append("%da%s" % (a1, comma(b1, b2)))
+ result.extend(map(lambda l: '> ' + l, b[b1:b2]))
+ elif op == 'replace':
+ result.append("%sc%s" % (comma(a1, a2), comma(b1, b2)))
+ result.extend(map(lambda l: '< ' + l, a[a1:a2]))
+ result.append('---')
+ result.extend(map(lambda l: '> ' + l, b[b1:b2]))
+ return result
+
+def diff_re(a, b, fromfile='', tofile='',
+ fromfiledate='', tofiledate='', n=3, lineterm='\n'):
+ """
+ A simple "diff" of two sets of lines when the expected lines
+ are regular expressions. This is a really dumb thing that
+ just compares each line in turn, so it doesn't look for
+ chunks of matching lines and the like--but at least it lets
+ you know exactly which line first didn't compare correctl...
+ """
+ result = []
+ diff = len(a) - len(b)
+ if diff < 0:
+ a = a + ['']*(-diff)
+ elif diff > 0:
+ b = b + ['']*diff
+ i = 0
+ for aline, bline in zip(a, b):
+ s = "^" + aline + "$"
+ try:
+ expr = re.compile(s)
+ except re.error, e:
+ msg = "Regular expression error in %s: %s"
+ raise re.error, msg % (repr(s), e[0])
+ if not expr.search(bline):
+ result.append("%sc%s" % (i+1, i+1))
+ result.append('< ' + repr(a[i]))
+ result.append('---')
+ result.append('> ' + repr(b[i]))
+ i = i+1
+ return result
+
+if os.name == 'java':
+
+ python_executable = os.path.join(sys.prefix, 'jython')
+
+else:
+
+ python_executable = sys.executable
+
+if sys.platform == 'win32':
+
+ default_sleep_seconds = 2
+
+ def where_is(file, path=None, pathext=None):
+ if path is None:
+ path = os.environ['PATH']
+ if is_String(path):
+ path = string.split(path, os.pathsep)
+ if pathext is None:
+ pathext = os.environ['PATHEXT']
+ if is_String(pathext):
+ pathext = string.split(pathext, os.pathsep)
+ for ext in pathext:
+ if string.lower(ext) == string.lower(file[-len(ext):]):
+ pathext = ['']
+ break
+ for dir in path:
+ f = os.path.join(dir, file)
+ for ext in pathext:
+ fext = f + ext
+ if os.path.isfile(fext):
+ return fext
+ return None
+
+else:
+
+ def where_is(file, path=None, pathext=None):
+ if path is None:
+ path = os.environ['PATH']
+ if is_String(path):
+ path = string.split(path, os.pathsep)
+ for dir in path:
+ f = os.path.join(dir, file)
+ if os.path.isfile(f):
+ try:
+ st = os.stat(f)
+ except OSError:
+ continue
+ if stat.S_IMODE(st[stat.ST_MODE]) & 0111:
+ return f
+ return None
+
+ default_sleep_seconds = 1
+
+
+
+try:
+ import subprocess
+except ImportError:
+ # The subprocess module doesn't exist in this version of Python,
+ # so we're going to cobble up something that looks just enough
+ # like its API for our purposes below.
+ import new
+
+ subprocess = new.module('subprocess')
+
+ subprocess.PIPE = 'PIPE'
+ subprocess.STDOUT = 'STDOUT'
+ subprocess.mswindows = (sys.platform == 'win32')
+
+ try:
+ import popen2
+ popen2.Popen3
+ except AttributeError:
+ class Popen3:
+ universal_newlines = 1
+ def __init__(self, command, **kw):
+ if sys.platform == 'win32' and command[0] == '"':
+ command = '"' + command + '"'
+ (stdin, stdout, stderr) = os.popen3(' ' + command)
+ self.stdin = stdin
+ self.stdout = stdout
+ self.stderr = stderr
+ def close_output(self):
+ self.stdout.close()
+ self.resultcode = self.stderr.close()
+ def wait(self):
+ resultcode = self.resultcode
+ if os.WIFEXITED(resultcode):
+ return os.WEXITSTATUS(resultcode)
+ elif os.WIFSIGNALED(resultcode):
+ return os.WTERMSIG(resultcode)
+ else:
+ return None
+
+ else:
+ try:
+ popen2.Popen4
+ except AttributeError:
+ # A cribbed Popen4 class, with some retrofitted code from
+ # the Python 1.5 Popen3 class methods to do certain things
+ # by hand.
+ class Popen4(popen2.Popen3):
+ childerr = None
+
+ def __init__(self, cmd, bufsize=-1):
+ p2cread, p2cwrite = os.pipe()
+ c2pread, c2pwrite = os.pipe()
+ self.pid = os.fork()
+ if self.pid == 0:
+ # Child
+ os.dup2(p2cread, 0)
+ os.dup2(c2pwrite, 1)
+ os.dup2(c2pwrite, 2)
+ for i in range(3, popen2.MAXFD):
+ try:
+ os.close(i)
+ except: pass
+ try:
+ os.execvp(cmd[0], cmd)
+ finally:
+ os._exit(1)
+ # Shouldn't come here, I guess
+ os._exit(1)
+ os.close(p2cread)
+ self.tochild = os.fdopen(p2cwrite, 'w', bufsize)
+ os.close(c2pwrite)
+ self.fromchild = os.fdopen(c2pread, 'r', bufsize)
+ popen2._active.append(self)
+
+ popen2.Popen4 = Popen4
+
+ class Popen3(popen2.Popen3, popen2.Popen4):
+ universal_newlines = 1
+ def __init__(self, command, **kw):
+ if kw.get('stderr') == 'STDOUT':
+ apply(popen2.Popen4.__init__, (self, command, 1))
+ else:
+ apply(popen2.Popen3.__init__, (self, command, 1))
+ self.stdin = self.tochild
+ self.stdout = self.fromchild
+ self.stderr = self.childerr
+ def wait(self, *args, **kw):
+ resultcode = apply(popen2.Popen3.wait, (self,)+args, kw)
+ if os.WIFEXITED(resultcode):
+ return os.WEXITSTATUS(resultcode)
+ elif os.WIFSIGNALED(resultcode):
+ return os.WTERMSIG(resultcode)
+ else:
+ return None
+
+ subprocess.Popen = Popen3
+
+
+
+# From Josiah Carlson,
+# ASPN : Python Cookbook : Module to allow Asynchronous subprocess use on Windows and Posix platforms
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554
+
+PIPE = subprocess.PIPE
+
+if subprocess.mswindows:
+ from win32file import ReadFile, WriteFile
+ from win32pipe import PeekNamedPipe
+ import msvcrt
+else:
+ import select
+ import fcntl
+
+ try: fcntl.F_GETFL
+ except AttributeError: fcntl.F_GETFL = 3
+
+ try: fcntl.F_SETFL
+ except AttributeError: fcntl.F_SETFL = 4
+
+class Popen(subprocess.Popen):
+ def recv(self, maxsize=None):
+ return self._recv('stdout', maxsize)
+
+ def recv_err(self, maxsize=None):
+ return self._recv('stderr', maxsize)
+
+ def send_recv(self, input='', maxsize=None):
+ return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
+
+ def get_conn_maxsize(self, which, maxsize):
+ if maxsize is None:
+ maxsize = 1024
+ elif maxsize < 1:
+ maxsize = 1
+ return getattr(self, which), maxsize
+
+ def _close(self, which):
+ getattr(self, which).close()
+ setattr(self, which, None)
+
+ if subprocess.mswindows:
+ def send(self, input):
+ if not self.stdin:
+ return None
+
+ try:
+ x = msvcrt.get_osfhandle(self.stdin.fileno())
+ (errCode, written) = WriteFile(x, input)
+ except ValueError:
+ return self._close('stdin')
+ except (subprocess.pywintypes.error, Exception), why:
+ if why[0] in (109, errno.ESHUTDOWN):
+ return self._close('stdin')
+ raise
+
+ return written
+
+ def _recv(self, which, maxsize):
+ conn, maxsize = self.get_conn_maxsize(which, maxsize)
+ if conn is None:
+ return None
+
+ try:
+ x = msvcrt.get_osfhandle(conn.fileno())
+ (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
+ if maxsize < nAvail:
+ nAvail = maxsize
+ if nAvail > 0:
+ (errCode, read) = ReadFile(x, nAvail, None)
+ except ValueError:
+ return self._close(which)
+ except (subprocess.pywintypes.error, Exception), why:
+ if why[0] in (109, errno.ESHUTDOWN):
+ return self._close(which)
+ raise
+
+ #if self.universal_newlines:
+ # read = self._translate_newlines(read)
+ return read
+
+ else:
+ def send(self, input):
+ if not self.stdin:
+ return None
+
+ if not select.select([], [self.stdin], [], 0)[1]:
+ return 0
+
+ try:
+ written = os.write(self.stdin.fileno(), input)
+ except OSError, why:
+ if why[0] == errno.EPIPE: #broken pipe
+ return self._close('stdin')
+ raise
+
+ return written
+
+ def _recv(self, which, maxsize):
+ conn, maxsize = self.get_conn_maxsize(which, maxsize)
+ if conn is None:
+ return None
+
+ try:
+ flags = fcntl.fcntl(conn, fcntl.F_GETFL)
+ except TypeError:
+ flags = None
+ else:
+ if not conn.closed:
+ fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
+
+ try:
+ if not select.select([conn], [], [], 0)[0]:
+ return ''
+
+ r = conn.read(maxsize)
+ if not r:
+ return self._close(which)
+
+ #if self.universal_newlines:
+ # r = self._translate_newlines(r)
+ return r
+ finally:
+ if not conn.closed and not flags is None:
+ fcntl.fcntl(conn, fcntl.F_SETFL, flags)
+
+disconnect_message = "Other end disconnected!"
+
+def recv_some(p, t=.1, e=1, tr=5, stderr=0):
+ if tr < 1:
+ tr = 1
+ x = time.time()+t
+ y = []
+ r = ''
+ pr = p.recv
+ if stderr:
+ pr = p.recv_err
+ while time.time() < x or r:
+ r = pr()
+ if r is None:
+ if e:
+ raise Exception(disconnect_message)
+ else:
+ break
+ elif r:
+ y.append(r)
+ else:
+ time.sleep(max((x-time.time())/tr, 0))
+ return ''.join(y)
+
+# TODO(3.0: rewrite to use memoryview()
+def send_all(p, data):
+ while len(data):
+ sent = p.send(data)
+ if sent is None:
+ raise Exception(disconnect_message)
+ data = buffer(data, sent)
+
+
+
+try:
+ object
+except NameError:
+ class object:
+ pass
+
+
+
+class TestCmd(object):
+ """Class TestCmd
+ """
+
+ def __init__(self, description = None,
+ program = None,
+ interpreter = None,
+ workdir = None,
+ subdir = None,
+ verbose = None,
+ match = None,
+ diff = None,
+ combine = 0,
+ universal_newlines = 1):
+ self._cwd = os.getcwd()
+ self.description_set(description)
+ self.program_set(program)
+ self.interpreter_set(interpreter)
+ if verbose is None:
+ try:
+ verbose = max( 0, int(os.environ.get('TESTCMD_VERBOSE', 0)) )
+ except ValueError:
+ verbose = 0
+ self.verbose_set(verbose)
+ self.combine = combine
+ self.universal_newlines = universal_newlines
+ if not match is None:
+ self.match_function = match
+ else:
+ self.match_function = match_re
+ if not diff is None:
+ self.diff_function = diff
+ else:
+ try:
+ difflib
+ except NameError:
+ pass
+ else:
+ self.diff_function = simple_diff
+ #self.diff_function = difflib.context_diff
+ #self.diff_function = difflib.unified_diff
+ self._dirlist = []
+ self._preserve = {'pass_test': 0, 'fail_test': 0, 'no_result': 0}
+ if os.environ.has_key('PRESERVE') and not os.environ['PRESERVE'] is '':
+ self._preserve['pass_test'] = os.environ['PRESERVE']
+ self._preserve['fail_test'] = os.environ['PRESERVE']
+ self._preserve['no_result'] = os.environ['PRESERVE']
+ else:
+ try:
+ self._preserve['pass_test'] = os.environ['PRESERVE_PASS']
+ except KeyError:
+ pass
+ try:
+ self._preserve['fail_test'] = os.environ['PRESERVE_FAIL']
+ except KeyError:
+ pass
+ try:
+ self._preserve['no_result'] = os.environ['PRESERVE_NO_RESULT']
+ except KeyError:
+ pass
+ self._stdout = []
+ self._stderr = []
+ self.status = None
+ self.condition = 'no_result'
+ self.workdir_set(workdir)
+ self.subdir(subdir)
+
+ def __del__(self):
+ self.cleanup()
+
+ def __repr__(self):
+ return "%x" % id(self)
+
+ banner_char = '='
+ banner_width = 80
+
+ def banner(self, s, width=None):
+ if width is None:
+ width = self.banner_width
+ return s + self.banner_char * (width - len(s))
+
+ if os.name == 'posix':
+
+ def escape(self, arg):
+ "escape shell special characters"
+ slash = '\\'
+ special = '"$'
+
+ arg = string.replace(arg, slash, slash+slash)
+ for c in special:
+ arg = string.replace(arg, c, slash+c)
+
+ if re_space.search(arg):
+ arg = '"' + arg + '"'
+ return arg
+
+ else:
+
+ # Windows does not allow special characters in file names
+ # anyway, so no need for an escape function, we will just quote
+ # the arg.
+ def escape(self, arg):
+ if re_space.search(arg):
+ arg = '"' + arg + '"'
+ return arg
+
+ def canonicalize(self, path):
+ if is_List(path):
+ path = apply(os.path.join, tuple(path))
+ if not os.path.isabs(path):
+ path = os.path.join(self.workdir, path)
+ return path
+
+ def chmod(self, path, mode):
+ """Changes permissions on the specified file or directory
+ path name."""
+ path = self.canonicalize(path)
+ os.chmod(path, mode)
+
+ def cleanup(self, condition = None):
+ """Removes any temporary working directories for the specified
+ TestCmd environment. If the environment variable PRESERVE was
+ set when the TestCmd environment was created, temporary working
+ directories are not removed. If any of the environment variables
+ PRESERVE_PASS, PRESERVE_FAIL, or PRESERVE_NO_RESULT were set
+ when the TestCmd environment was created, then temporary working
+ directories are not removed if the test passed, failed, or had
+ no result, respectively. Temporary working directories are also
+ preserved for conditions specified via the preserve method.
+
+ Typically, this method is not called directly, but is used when
+ the script exits to clean up temporary working directories as
+ appropriate for the exit status.
+ """
+ if not self._dirlist:
+ return
+ os.chdir(self._cwd)
+ self.workdir = None
+ if condition is None:
+ condition = self.condition
+ if self._preserve[condition]:
+ for dir in self._dirlist:
+ print "Preserved directory", dir
+ else:
+ list = self._dirlist[:]
+ list.reverse()
+ for dir in list:
+ self.writable(dir, 1)
+ shutil.rmtree(dir, ignore_errors = 1)
+ self._dirlist = []
+
+ try:
+ global _Cleanup
+ _Cleanup.remove(self)
+ except (AttributeError, ValueError):
+ pass
+
+ def command_args(self, program = None,
+ interpreter = None,
+ arguments = None):
+ if program:
+ if type(program) == type('') and not os.path.isabs(program):
+ program = os.path.join(self._cwd, program)
+ else:
+ program = self.program
+ if not interpreter:
+ interpreter = self.interpreter
+ if not type(program) in [type([]), type(())]:
+ program = [program]
+ cmd = list(program)
+ if interpreter:
+ if not type(interpreter) in [type([]), type(())]:
+ interpreter = [interpreter]
+ cmd = list(interpreter) + cmd
+ if arguments:
+ if type(arguments) == type(''):
+ arguments = string.split(arguments)
+ cmd.extend(arguments)
+ return cmd
+
+ def description_set(self, description):
+ """Set the description of the functionality being tested.
+ """
+ self.description = description
+
+ try:
+ difflib
+ except NameError:
+ def diff(self, a, b, name, *args, **kw):
+ print self.banner('Expected %s' % name)
+ print a
+ print self.banner('Actual %s' % name)
+ print b
+ else:
+ def diff(self, a, b, name, *args, **kw):
+ print self.banner(name)
+ args = (a.splitlines(), b.splitlines()) + args
+ lines = apply(self.diff_function, args, kw)
+ for l in lines:
+ print l
+
+ def fail_test(self, condition = 1, function = None, skip = 0):
+ """Cause the test to fail.
+ """
+ if not condition:
+ return
+ self.condition = 'fail_test'
+ fail_test(self = self,
+ condition = condition,
+ function = function,
+ skip = skip)
+
+ def interpreter_set(self, interpreter):
+ """Set the program to be used to interpret the program
+ under test as a script.
+ """
+ self.interpreter = interpreter
+
+ def match(self, lines, matches):
+ """Compare actual and expected file contents.
+ """
+ return self.match_function(lines, matches)
+
+ def match_exact(self, lines, matches):
+ """Compare actual and expected file contents.
+ """
+ return match_exact(lines, matches)
+
+ def match_re(self, lines, res):
+ """Compare actual and expected file contents.
+ """
+ return match_re(lines, res)
+
+ def match_re_dotall(self, lines, res):
+ """Compare actual and expected file contents.
+ """
+ return match_re_dotall(lines, res)
+
+ def no_result(self, condition = 1, function = None, skip = 0):
+ """Report that the test could not be run.
+ """
+ if not condition:
+ return
+ self.condition = 'no_result'
+ no_result(self = self,
+ condition = condition,
+ function = function,
+ skip = skip)
+
+ def pass_test(self, condition = 1, function = None):
+ """Cause the test to pass.
+ """
+ if not condition:
+ return
+ self.condition = 'pass_test'
+ pass_test(self = self, condition = condition, function = function)
+
+ def preserve(self, *conditions):
+ """Arrange for the temporary working directories for the
+ specified TestCmd environment to be preserved for one or more
+ conditions. If no conditions are specified, arranges for
+ the temporary working directories to be preserved for all
+ conditions.
+ """
+ if conditions is ():
+ conditions = ('pass_test', 'fail_test', 'no_result')
+ for cond in conditions:
+ self._preserve[cond] = 1
+
+ def program_set(self, program):
+ """Set the executable program or script to be tested.
+ """
+ if program and not os.path.isabs(program):
+ program = os.path.join(self._cwd, program)
+ self.program = program
+
+ def read(self, file, mode = 'rb'):
+ """Reads and returns the contents of the specified file name.
+ The file name may be a list, in which case the elements are
+ concatenated with the os.path.join() method. The file is
+ assumed to be under the temporary working directory unless it
+ is an absolute path name. The I/O mode for the file may
+ be specified; it must begin with an 'r'. The default is
+ 'rb' (binary read).
+ """
+ file = self.canonicalize(file)
+ if mode[0] != 'r':
+ raise ValueError, "mode must begin with 'r'"
+ return open(file, mode).read()
+
+ def rmdir(self, dir):
+ """Removes the specified dir name.
+ The dir name may be a list, in which case the elements are
+ concatenated with the os.path.join() method. The dir is
+ assumed to be under the temporary working directory unless it
+ is an absolute path name.
+ The dir must be empty.
+ """
+ dir = self.canonicalize(dir)
+ os.rmdir(dir)
+
+ def start(self, program = None,
+ interpreter = None,
+ arguments = None,
+ universal_newlines = None,
+ **kw):
+ """
+ Starts a program or script for the test environment.
+
+ The specified program will have the original directory
+ prepended unless it is enclosed in a [list].
+ """
+ cmd = self.command_args(program, interpreter, arguments)
+ cmd_string = string.join(map(self.escape, cmd), ' ')
+ if self.verbose:
+ sys.stderr.write(cmd_string + "\n")
+ if universal_newlines is None:
+ universal_newlines = self.universal_newlines
+
+ # On Windows, if we make stdin a pipe when we plan to send
+ # no input, and the test program exits before
+ # Popen calls msvcrt.open_osfhandle, that call will fail.
+ # So don't use a pipe for stdin if we don't need one.
+ stdin = kw.get('stdin', None)
+ if stdin is not None:
+ stdin = subprocess.PIPE
+
+ combine = kw.get('combine', self.combine)
+ if combine:
+ stderr_value = subprocess.STDOUT
+ else:
+ stderr_value = subprocess.PIPE
+
+ return Popen(cmd,
+ stdin=stdin,
+ stdout=subprocess.PIPE,
+ stderr=stderr_value,
+ universal_newlines=universal_newlines)
+
+ def finish(self, popen, **kw):
+ """
+ Finishes and waits for the process being run under control of
+ the specified popen argument, recording the exit status,
+ standard output and error output.
+ """
+ popen.stdin.close()
+ self.status = popen.wait()
+ if not self.status:
+ self.status = 0
+ self._stdout.append(popen.stdout.read())
+ if popen.stderr:
+ stderr = popen.stderr.read()
+ else:
+ stderr = ''
+ self._stderr.append(stderr)
+
+ def run(self, program = None,
+ interpreter = None,
+ arguments = None,
+ chdir = None,
+ stdin = None,
+ universal_newlines = None):
+ """Runs a test of the program or script for the test
+ environment. Standard output and error output are saved for
+ future retrieval via the stdout() and stderr() methods.
+
+ The specified program will have the original directory
+ prepended unless it is enclosed in a [list].
+ """
+ if chdir:
+ oldcwd = os.getcwd()
+ if not os.path.isabs(chdir):
+ chdir = os.path.join(self.workpath(chdir))
+ if self.verbose:
+ sys.stderr.write("chdir(" + chdir + ")\n")
+ os.chdir(chdir)
+ p = self.start(program,
+ interpreter,
+ arguments,
+ universal_newlines,
+ stdin=stdin)
+ if stdin:
+ if is_List(stdin):
+ for line in stdin:
+ p.stdin.write(line)
+ else:
+ p.stdin.write(stdin)
+ p.stdin.close()
+
+ out = p.stdout.read()
+ if p.stderr is None:
+ err = ''
+ else:
+ err = p.stderr.read()
+ try:
+ close_output = p.close_output
+ except AttributeError:
+ p.stdout.close()
+ if not p.stderr is None:
+ p.stderr.close()
+ else:
+ close_output()
+
+ self._stdout.append(out)
+ self._stderr.append(err)
+
+ self.status = p.wait()
+ if not self.status:
+ self.status = 0
+
+ if chdir:
+ os.chdir(oldcwd)
+ if self.verbose >= 2:
+ write = sys.stdout.write
+ write('============ STATUS: %d\n' % self.status)
+ out = self.stdout()
+ if out or self.verbose >= 3:
+ write('============ BEGIN STDOUT (len=%d):\n' % len(out))
+ write(out)
+ write('============ END STDOUT\n')
+ err = self.stderr()
+ if err or self.verbose >= 3:
+ write('============ BEGIN STDERR (len=%d)\n' % len(err))
+ write(err)
+ write('============ END STDERR\n')
+
+ def sleep(self, seconds = default_sleep_seconds):
+ """Sleeps at least the specified number of seconds. If no
+ number is specified, sleeps at least the minimum number of
+ seconds necessary to advance file time stamps on the current
+ system. Sleeping more seconds is all right.
+ """
+ time.sleep(seconds)
+
+ def stderr(self, run = None):
+ """Returns the error output from the specified run number.
+ If there is no specified run number, then returns the error
+ output of the last run. If the run number is less than zero,
+ then returns the error output from that many runs back from the
+ current run.
+ """
+ if not run:
+ run = len(self._stderr)
+ elif run < 0:
+ run = len(self._stderr) + run
+ run = run - 1
+ return self._stderr[run]
+
+ def stdout(self, run = None):
+ """Returns the standard output from the specified run number.
+ If there is no specified run number, then returns the standard
+ output of the last run. If the run number is less than zero,
+ then returns the standard output from that many runs back from
+ the current run.
+ """
+ if not run:
+ run = len(self._stdout)
+ elif run < 0:
+ run = len(self._stdout) + run
+ run = run - 1
+ return self._stdout[run]
+
+ def subdir(self, *subdirs):
+ """Create new subdirectories under the temporary working
+ directory, one for each argument. An argument may be a list,
+ in which case the list elements are concatenated using the
+ os.path.join() method. Subdirectories multiple levels deep
+ must be created using a separate argument for each level:
+
+ test.subdir('sub', ['sub', 'dir'], ['sub', 'dir', 'ectory'])
+
+ Returns the number of subdirectories actually created.
+ """
+ count = 0
+ for sub in subdirs:
+ if sub is None:
+ continue
+ if is_List(sub):
+ sub = apply(os.path.join, tuple(sub))
+ new = os.path.join(self.workdir, sub)
+ try:
+ os.mkdir(new)
+ except OSError:
+ pass
+ else:
+ count = count + 1
+ return count
+
+ def symlink(self, target, link):
+ """Creates a symlink to the specified target.
+ The link name may be a list, in which case the elements are
+ concatenated with the os.path.join() method. The link is
+ assumed to be under the temporary working directory unless it
+ is an absolute path name. The target is *not* assumed to be
+ under the temporary working directory.
+ """
+ link = self.canonicalize(link)
+ os.symlink(target, link)
+
+ def tempdir(self, path=None):
+ """Creates a temporary directory.
+ A unique directory name is generated if no path name is specified.
+ The directory is created, and will be removed when the TestCmd
+ object is destroyed.
+ """
+ if path is None:
+ try:
+ path = tempfile.mktemp(prefix=tempfile.template)
+ except TypeError:
+ path = tempfile.mktemp()
+ os.mkdir(path)
+
+ # Symlinks in the path will report things
+ # differently from os.getcwd(), so chdir there
+ # and back to fetch the canonical path.
+ cwd = os.getcwd()
+ try:
+ os.chdir(path)
+ path = os.getcwd()
+ finally:
+ os.chdir(cwd)
+
+ # Uppercase the drive letter since the case of drive
+ # letters is pretty much random on win32:
+ drive,rest = os.path.splitdrive(path)
+ if drive:
+ path = string.upper(drive) + rest
+
+ #
+ self._dirlist.append(path)
+ global _Cleanup
+ try:
+ _Cleanup.index(self)
+ except ValueError:
+ _Cleanup.append(self)
+
+ return path
+
+ def touch(self, path, mtime=None):
+ """Updates the modification time on the specified file or
+ directory path name. The default is to update to the
+ current time if no explicit modification time is specified.
+ """
+ path = self.canonicalize(path)
+ atime = os.path.getatime(path)
+ if mtime is None:
+ mtime = time.time()
+ os.utime(path, (atime, mtime))
+
+ def unlink(self, file):
+ """Unlinks the specified file name.
+ The file name may be a list, in which case the elements are
+ concatenated with the os.path.join() method. The file is
+ assumed to be under the temporary working directory unless it
+ is an absolute path name.
+ """
+ file = self.canonicalize(file)
+ os.unlink(file)
+
+ def verbose_set(self, verbose):
+ """Set the verbose level.
+ """
+ self.verbose = verbose
+
+ def where_is(self, file, path=None, pathext=None):
+ """Find an executable file.
+ """
+ if is_List(file):
+ file = apply(os.path.join, tuple(file))
+ if not os.path.isabs(file):
+ file = where_is(file, path, pathext)
+ return file
+
+ def workdir_set(self, path):
+ """Creates a temporary working directory with the specified
+ path name. If the path is a null string (''), a unique
+ directory name is created.
+ """
+ if (path != None):
+ if path == '':
+ path = None
+ path = self.tempdir(path)
+ self.workdir = path
+
+ def workpath(self, *args):
+ """Returns the absolute path name to a subdirectory or file
+ within the current temporary working directory. Concatenates
+ the temporary working directory name with the specified
+ arguments using the os.path.join() method.
+ """
+ return apply(os.path.join, (self.workdir,) + tuple(args))
+
+ def readable(self, top, read=1):
+ """Make the specified directory tree readable (read == 1)
+ or not (read == None).
+
+ This method has no effect on Windows systems, which use a
+ completely different mechanism to control file readability.
+ """
+
+ if sys.platform == 'win32':
+ return
+
+ if read:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|stat.S_IREAD))
+ else:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IREAD))
+
+ if os.path.isfile(top):
+ # If it's a file, that's easy, just chmod it.
+ do_chmod(top)
+ elif read:
+ # It's a directory and we're trying to turn on read
+ # permission, so it's also pretty easy, just chmod the
+ # directory and then chmod every entry on our walk down the
+ # tree. Because os.path.walk() is top-down, we'll enable
+ # read permission on any directories that have it disabled
+ # before os.path.walk() tries to list their contents.
+ do_chmod(top)
+
+ def chmod_entries(arg, dirname, names, do_chmod=do_chmod):
+ for n in names:
+ do_chmod(os.path.join(dirname, n))
+
+ os.path.walk(top, chmod_entries, None)
+ else:
+ # It's a directory and we're trying to turn off read
+ # permission, which means we have to chmod the directoreis
+ # in the tree bottom-up, lest disabling read permission from
+ # the top down get in the way of being able to get at lower
+ # parts of the tree. But os.path.walk() visits things top
+ # down, so we just use an object to collect a list of all
+ # of the entries in the tree, reverse the list, and then
+ # chmod the reversed (bottom-up) list.
+ col = Collector(top)
+ os.path.walk(top, col, None)
+ col.entries.reverse()
+ for d in col.entries: do_chmod(d)
+
+ def writable(self, top, write=1):
+ """Make the specified directory tree writable (write == 1)
+ or not (write == None).
+ """
+
+ if sys.platform == 'win32':
+
+ if write:
+ def do_chmod(fname):
+ try: os.chmod(fname, stat.S_IWRITE)
+ except OSError: pass
+ else:
+ def do_chmod(fname):
+ try: os.chmod(fname, stat.S_IREAD)
+ except OSError: pass
+
+ else:
+
+ if write:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|0200))
+ else:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~0200))
+
+ if os.path.isfile(top):
+ do_chmod(top)
+ else:
+ col = Collector(top)
+ os.path.walk(top, col, None)
+ for d in col.entries: do_chmod(d)
+
+ def executable(self, top, execute=1):
+ """Make the specified directory tree executable (execute == 1)
+ or not (execute == None).
+
+ This method has no effect on Windows systems, which use a
+ completely different mechanism to control file executability.
+ """
+
+ if sys.platform == 'win32':
+ return
+
+ if execute:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]|stat.S_IEXEC))
+ else:
+ def do_chmod(fname):
+ try: st = os.stat(fname)
+ except OSError: pass
+ else: os.chmod(fname, stat.S_IMODE(st[stat.ST_MODE]&~stat.S_IEXEC))
+
+ if os.path.isfile(top):
+ # If it's a file, that's easy, just chmod it.
+ do_chmod(top)
+ elif execute:
+ # It's a directory and we're trying to turn on execute
+ # permission, so it's also pretty easy, just chmod the
+ # directory and then chmod every entry on our walk down the
+ # tree. Because os.path.walk() is top-down, we'll enable
+ # execute permission on any directories that have it disabled
+ # before os.path.walk() tries to list their contents.
+ do_chmod(top)
+
+ def chmod_entries(arg, dirname, names, do_chmod=do_chmod):
+ for n in names:
+ do_chmod(os.path.join(dirname, n))
+
+ os.path.walk(top, chmod_entries, None)
+ else:
+ # It's a directory and we're trying to turn off execute
+ # permission, which means we have to chmod the directories
+ # in the tree bottom-up, lest disabling execute permission from
+ # the top down get in the way of being able to get at lower
+ # parts of the tree. But os.path.walk() visits things top
+ # down, so we just use an object to collect a list of all
+ # of the entries in the tree, reverse the list, and then
+ # chmod the reversed (bottom-up) list.
+ col = Collector(top)
+ os.path.walk(top, col, None)
+ col.entries.reverse()
+ for d in col.entries: do_chmod(d)
+
+ def write(self, file, content, mode = 'wb'):
+ """Writes the specified content text (second argument) to the
+ specified file name (first argument). The file name may be
+ a list, in which case the elements are concatenated with the
+ os.path.join() method. The file is created under the temporary
+ working directory. Any subdirectories in the path must already
+ exist. The I/O mode for the file may be specified; it must
+ begin with a 'w'. The default is 'wb' (binary write).
+ """
+ file = self.canonicalize(file)
+ if mode[0] != 'w':
+ raise ValueError, "mode must begin with 'w'"
+ open(file, mode).write(content)
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/Source/ThirdParty/gyp/test/lib/TestCommon.py b/Source/ThirdParty/gyp/test/lib/TestCommon.py
new file mode 100644
index 000000000..4aa7185a2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/lib/TestCommon.py
@@ -0,0 +1,581 @@
+"""
+TestCommon.py: a testing framework for commands and scripts
+ with commonly useful error handling
+
+The TestCommon module provides a simple, high-level interface for writing
+tests of executable commands and scripts, especially commands and scripts
+that interact with the file system. All methods throw exceptions and
+exit on failure, with useful error messages. This makes a number of
+explicit checks unnecessary, making the test scripts themselves simpler
+to write and easier to read.
+
+The TestCommon class is a subclass of the TestCmd class. In essence,
+TestCommon is a wrapper that handles common TestCmd error conditions in
+useful ways. You can use TestCommon directly, or subclass it for your
+program and add additional (or override) methods to tailor it to your
+program's specific needs. Alternatively, the TestCommon class serves
+as a useful example of how to define your own TestCmd subclass.
+
+As a subclass of TestCmd, TestCommon provides access to all of the
+variables and methods from the TestCmd module. Consequently, you can
+use any variable or method documented in the TestCmd module without
+having to explicitly import TestCmd.
+
+A TestCommon environment object is created via the usual invocation:
+
+ import TestCommon
+ test = TestCommon.TestCommon()
+
+You can use all of the TestCmd keyword arguments when instantiating a
+TestCommon object; see the TestCmd documentation for details.
+
+Here is an overview of the methods and keyword arguments that are
+provided by the TestCommon class:
+
+ test.must_be_writable('file1', ['file2', ...])
+
+ test.must_contain('file', 'required text\n')
+
+ test.must_contain_all_lines(output, lines, ['title', find])
+
+ test.must_contain_any_line(output, lines, ['title', find])
+
+ test.must_exist('file1', ['file2', ...])
+
+ test.must_match('file', "expected contents\n")
+
+ test.must_not_be_writable('file1', ['file2', ...])
+
+ test.must_not_contain('file', 'banned text\n')
+
+ test.must_not_contain_any_line(output, lines, ['title', find])
+
+ test.must_not_exist('file1', ['file2', ...])
+
+ test.run(options = "options to be prepended to arguments",
+ stdout = "expected standard output from the program",
+ stderr = "expected error output from the program",
+ status = expected_status,
+ match = match_function)
+
+The TestCommon module also provides the following variables
+
+ TestCommon.python_executable
+ TestCommon.exe_suffix
+ TestCommon.obj_suffix
+ TestCommon.shobj_prefix
+ TestCommon.shobj_suffix
+ TestCommon.lib_prefix
+ TestCommon.lib_suffix
+ TestCommon.dll_prefix
+ TestCommon.dll_suffix
+
+"""
+
+# Copyright 2000-2010 Steven Knight
+# This module is free software, and you may redistribute it and/or modify
+# it under the same terms as Python itself, so long as this copyright message
+# and disclaimer are retained in their original form.
+#
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+# SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
+# THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+# THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS,
+# AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
+# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+__author__ = "Steven Knight <knight at baldmt dot com>"
+__revision__ = "TestCommon.py 0.37.D001 2010/01/11 16:55:50 knight"
+__version__ = "0.37"
+
+import copy
+import os
+import os.path
+import stat
+import string
+import sys
+import types
+import UserList
+
+from TestCmd import *
+from TestCmd import __all__
+
+__all__.extend([ 'TestCommon',
+ 'exe_suffix',
+ 'obj_suffix',
+ 'shobj_prefix',
+ 'shobj_suffix',
+ 'lib_prefix',
+ 'lib_suffix',
+ 'dll_prefix',
+ 'dll_suffix',
+ ])
+
+# Variables that describe the prefixes and suffixes on this system.
+if sys.platform == 'win32':
+ exe_suffix = '.exe'
+ obj_suffix = '.obj'
+ shobj_suffix = '.obj'
+ shobj_prefix = ''
+ lib_prefix = ''
+ lib_suffix = '.lib'
+ dll_prefix = ''
+ dll_suffix = '.dll'
+elif sys.platform == 'cygwin':
+ exe_suffix = '.exe'
+ obj_suffix = '.o'
+ shobj_suffix = '.os'
+ shobj_prefix = ''
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = ''
+ dll_suffix = '.dll'
+elif string.find(sys.platform, 'irix') != -1:
+ exe_suffix = ''
+ obj_suffix = '.o'
+ shobj_suffix = '.o'
+ shobj_prefix = ''
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = 'lib'
+ dll_suffix = '.so'
+elif string.find(sys.platform, 'darwin') != -1:
+ exe_suffix = ''
+ obj_suffix = '.o'
+ shobj_suffix = '.os'
+ shobj_prefix = ''
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = 'lib'
+ dll_suffix = '.dylib'
+elif string.find(sys.platform, 'sunos') != -1:
+ exe_suffix = ''
+ obj_suffix = '.o'
+ shobj_suffix = '.os'
+ shobj_prefix = 'so_'
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = 'lib'
+ dll_suffix = '.dylib'
+else:
+ exe_suffix = ''
+ obj_suffix = '.o'
+ shobj_suffix = '.os'
+ shobj_prefix = ''
+ lib_prefix = 'lib'
+ lib_suffix = '.a'
+ dll_prefix = 'lib'
+ dll_suffix = '.so'
+
+def is_List(e):
+ return type(e) is types.ListType \
+ or isinstance(e, UserList.UserList)
+
+def is_writable(f):
+ mode = os.stat(f)[stat.ST_MODE]
+ return mode & stat.S_IWUSR
+
+def separate_files(flist):
+ existing = []
+ missing = []
+ for f in flist:
+ if os.path.exists(f):
+ existing.append(f)
+ else:
+ missing.append(f)
+ return existing, missing
+
+if os.name == 'posix':
+ def _failed(self, status = 0):
+ if self.status is None or status is None:
+ return None
+ return _status(self) != status
+ def _status(self):
+ return self.status
+elif os.name == 'nt':
+ def _failed(self, status = 0):
+ return not (self.status is None or status is None) and \
+ self.status != status
+ def _status(self):
+ return self.status
+
+class TestCommon(TestCmd):
+
+ # Additional methods from the Perl Test::Cmd::Common module
+ # that we may wish to add in the future:
+ #
+ # $test->subdir('subdir', ...);
+ #
+ # $test->copy('src_file', 'dst_file');
+
+ def __init__(self, **kw):
+ """Initialize a new TestCommon instance. This involves just
+ calling the base class initialization, and then changing directory
+ to the workdir.
+ """
+ apply(TestCmd.__init__, [self], kw)
+ os.chdir(self.workdir)
+
+ def must_be_writable(self, *files):
+ """Ensures that the specified file(s) exist and are writable.
+ An individual file can be specified as a list of directory names,
+ in which case the pathname will be constructed by concatenating
+ them. Exits FAILED if any of the files does not exist or is
+ not writable.
+ """
+ files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+ existing, missing = separate_files(files)
+ unwritable = filter(lambda x, iw=is_writable: not iw(x), existing)
+ if missing:
+ print "Missing files: `%s'" % string.join(missing, "', `")
+ if unwritable:
+ print "Unwritable files: `%s'" % string.join(unwritable, "', `")
+ self.fail_test(missing + unwritable)
+
+ def must_contain(self, file, required, mode = 'rb'):
+ """Ensures that the specified file contains the required text.
+ """
+ file_contents = self.read(file, mode)
+ contains = (string.find(file_contents, required) != -1)
+ if not contains:
+ print "File `%s' does not contain required string." % file
+ print self.banner('Required string ')
+ print required
+ print self.banner('%s contents ' % file)
+ print file_contents
+ self.fail_test(not contains)
+
+ def must_contain_all_lines(self, output, lines, title=None, find=None):
+ """Ensures that the specified output string (first argument)
+ contains all of the specified lines (second argument).
+
+ An optional third argument can be used to describe the type
+ of output being searched, and only shows up in failure output.
+
+ An optional fourth argument can be used to supply a different
+ function, of the form "find(line, output), to use when searching
+ for lines in the output.
+ """
+ if find is None:
+ find = lambda o, l: string.find(o, l) != -1
+ missing = []
+ for line in lines:
+ if not find(output, line):
+ missing.append(line)
+
+ if missing:
+ if title is None:
+ title = 'output'
+ sys.stdout.write("Missing expected lines from %s:\n" % title)
+ for line in missing:
+ sys.stdout.write(' ' + repr(line) + '\n')
+ sys.stdout.write(self.banner(title + ' '))
+ sys.stdout.write(output)
+ self.fail_test()
+
+ def must_contain_any_line(self, output, lines, title=None, find=None):
+ """Ensures that the specified output string (first argument)
+ contains at least one of the specified lines (second argument).
+
+ An optional third argument can be used to describe the type
+ of output being searched, and only shows up in failure output.
+
+ An optional fourth argument can be used to supply a different
+ function, of the form "find(line, output), to use when searching
+ for lines in the output.
+ """
+ if find is None:
+ find = lambda o, l: string.find(o, l) != -1
+ for line in lines:
+ if find(output, line):
+ return
+
+ if title is None:
+ title = 'output'
+ sys.stdout.write("Missing any expected line from %s:\n" % title)
+ for line in lines:
+ sys.stdout.write(' ' + repr(line) + '\n')
+ sys.stdout.write(self.banner(title + ' '))
+ sys.stdout.write(output)
+ self.fail_test()
+
+ def must_contain_lines(self, lines, output, title=None):
+ # Deprecated; retain for backwards compatibility.
+ return self.must_contain_all_lines(output, lines, title)
+
+ def must_exist(self, *files):
+ """Ensures that the specified file(s) must exist. An individual
+ file be specified as a list of directory names, in which case the
+ pathname will be constructed by concatenating them. Exits FAILED
+ if any of the files does not exist.
+ """
+ files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+ missing = filter(lambda x: not os.path.exists(x), files)
+ if missing:
+ print "Missing files: `%s'" % string.join(missing, "', `")
+ self.fail_test(missing)
+
+ def must_match(self, file, expect, mode = 'rb'):
+ """Matches the contents of the specified file (first argument)
+ against the expected contents (second argument). The expected
+ contents are a list of lines or a string which will be split
+ on newlines.
+ """
+ file_contents = self.read(file, mode)
+ try:
+ self.fail_test(not self.match(file_contents, expect))
+ except KeyboardInterrupt:
+ raise
+ except:
+ print "Unexpected contents of `%s'" % file
+ self.diff(expect, file_contents, 'contents ')
+ raise
+
+ def must_not_contain(self, file, banned, mode = 'rb'):
+ """Ensures that the specified file doesn't contain the banned text.
+ """
+ file_contents = self.read(file, mode)
+ contains = (string.find(file_contents, banned) != -1)
+ if contains:
+ print "File `%s' contains banned string." % file
+ print self.banner('Banned string ')
+ print banned
+ print self.banner('%s contents ' % file)
+ print file_contents
+ self.fail_test(contains)
+
+ def must_not_contain_any_line(self, output, lines, title=None, find=None):
+ """Ensures that the specified output string (first argument)
+ does not contain any of the specified lines (second argument).
+
+ An optional third argument can be used to describe the type
+ of output being searched, and only shows up in failure output.
+
+ An optional fourth argument can be used to supply a different
+ function, of the form "find(line, output), to use when searching
+ for lines in the output.
+ """
+ if find is None:
+ find = lambda o, l: string.find(o, l) != -1
+ unexpected = []
+ for line in lines:
+ if find(output, line):
+ unexpected.append(line)
+
+ if unexpected:
+ if title is None:
+ title = 'output'
+ sys.stdout.write("Unexpected lines in %s:\n" % title)
+ for line in unexpected:
+ sys.stdout.write(' ' + repr(line) + '\n')
+ sys.stdout.write(self.banner(title + ' '))
+ sys.stdout.write(output)
+ self.fail_test()
+
+ def must_not_contain_lines(self, lines, output, title=None):
+ return self.must_not_contain_any_line(output, lines, title)
+
+ def must_not_exist(self, *files):
+ """Ensures that the specified file(s) must not exist.
+ An individual file be specified as a list of directory names, in
+ which case the pathname will be constructed by concatenating them.
+ Exits FAILED if any of the files exists.
+ """
+ files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+ existing = filter(os.path.exists, files)
+ if existing:
+ print "Unexpected files exist: `%s'" % string.join(existing, "', `")
+ self.fail_test(existing)
+
+
+ def must_not_be_writable(self, *files):
+ """Ensures that the specified file(s) exist and are not writable.
+ An individual file can be specified as a list of directory names,
+ in which case the pathname will be constructed by concatenating
+ them. Exits FAILED if any of the files does not exist or is
+ writable.
+ """
+ files = map(lambda x: is_List(x) and apply(os.path.join, x) or x, files)
+ existing, missing = separate_files(files)
+ writable = filter(is_writable, existing)
+ if missing:
+ print "Missing files: `%s'" % string.join(missing, "', `")
+ if writable:
+ print "Writable files: `%s'" % string.join(writable, "', `")
+ self.fail_test(missing + writable)
+
+ def _complete(self, actual_stdout, expected_stdout,
+ actual_stderr, expected_stderr, status, match):
+ """
+ Post-processes running a subcommand, checking for failure
+ status and displaying output appropriately.
+ """
+ if _failed(self, status):
+ expect = ''
+ if status != 0:
+ expect = " (expected %s)" % str(status)
+ print "%s returned %s%s" % (self.program, str(_status(self)), expect)
+ print self.banner('STDOUT ')
+ print actual_stdout
+ print self.banner('STDERR ')
+ print actual_stderr
+ self.fail_test()
+ if not expected_stdout is None and not match(actual_stdout, expected_stdout):
+ self.diff(expected_stdout, actual_stdout, 'STDOUT ')
+ if actual_stderr:
+ print self.banner('STDERR ')
+ print actual_stderr
+ self.fail_test()
+ if not expected_stderr is None and not match(actual_stderr, expected_stderr):
+ print self.banner('STDOUT ')
+ print actual_stdout
+ self.diff(expected_stderr, actual_stderr, 'STDERR ')
+ self.fail_test()
+
+ def start(self, program = None,
+ interpreter = None,
+ arguments = None,
+ universal_newlines = None,
+ **kw):
+ """
+ Starts a program or script for the test environment.
+
+ This handles the "options" keyword argument and exceptions.
+ """
+ try:
+ options = kw['options']
+ del kw['options']
+ except KeyError:
+ pass
+ else:
+ if options:
+ if arguments is None:
+ arguments = options
+ else:
+ arguments = options + " " + arguments
+ try:
+ return apply(TestCmd.start,
+ (self, program, interpreter, arguments, universal_newlines),
+ kw)
+ except KeyboardInterrupt:
+ raise
+ except Exception, e:
+ print self.banner('STDOUT ')
+ try:
+ print self.stdout()
+ except IndexError:
+ pass
+ print self.banner('STDERR ')
+ try:
+ print self.stderr()
+ except IndexError:
+ pass
+ cmd_args = self.command_args(program, interpreter, arguments)
+ sys.stderr.write('Exception trying to execute: %s\n' % cmd_args)
+ raise e
+
+ def finish(self, popen, stdout = None, stderr = '', status = 0, **kw):
+ """
+ Finishes and waits for the process being run under control of
+ the specified popen argument. Additional arguments are similar
+ to those of the run() method:
+
+ stdout The expected standard output from
+ the command. A value of None means
+ don't test standard output.
+
+ stderr The expected error output from
+ the command. A value of None means
+ don't test error output.
+
+ status The expected exit status from the
+ command. A value of None means don't
+ test exit status.
+ """
+ apply(TestCmd.finish, (self, popen,), kw)
+ match = kw.get('match', self.match)
+ self._complete(self.stdout(), stdout,
+ self.stderr(), stderr, status, match)
+
+ def run(self, options = None, arguments = None,
+ stdout = None, stderr = '', status = 0, **kw):
+ """Runs the program under test, checking that the test succeeded.
+
+ The arguments are the same as the base TestCmd.run() method,
+ with the addition of:
+
+ options Extra options that get appended to the beginning
+ of the arguments.
+
+ stdout The expected standard output from
+ the command. A value of None means
+ don't test standard output.
+
+ stderr The expected error output from
+ the command. A value of None means
+ don't test error output.
+
+ status The expected exit status from the
+ command. A value of None means don't
+ test exit status.
+
+ By default, this expects a successful exit (status = 0), does
+ not test standard output (stdout = None), and expects that error
+ output is empty (stderr = "").
+ """
+ if options:
+ if arguments is None:
+ arguments = options
+ else:
+ arguments = options + " " + arguments
+ kw['arguments'] = arguments
+ try:
+ match = kw['match']
+ del kw['match']
+ except KeyError:
+ match = self.match
+ apply(TestCmd.run, [self], kw)
+ self._complete(self.stdout(), stdout,
+ self.stderr(), stderr, status, match)
+
+ def skip_test(self, message="Skipping test.\n"):
+ """Skips a test.
+
+ Proper test-skipping behavior is dependent on the external
+ TESTCOMMON_PASS_SKIPS environment variable. If set, we treat
+ the skip as a PASS (exit 0), and otherwise treat it as NO RESULT.
+ In either case, we print the specified message as an indication
+ that the substance of the test was skipped.
+
+ (This was originally added to support development under Aegis.
+ Technically, skipping a test is a NO RESULT, but Aegis would
+ treat that as a test failure and prevent the change from going to
+ the next step. Since we ddn't want to force anyone using Aegis
+ to have to install absolutely every tool used by the tests, we
+ would actually report to Aegis that a skipped test has PASSED
+ so that the workflow isn't held up.)
+ """
+ if message:
+ sys.stdout.write(message)
+ sys.stdout.flush()
+ pass_skips = os.environ.get('TESTCOMMON_PASS_SKIPS')
+ if pass_skips in [None, 0, '0']:
+ # skip=1 means skip this function when showing where this
+ # result came from. They only care about the line where the
+ # script called test.skip_test(), not the line number where
+ # we call test.no_result().
+ self.no_result(skip=1)
+ else:
+ # We're under the development directory for this change,
+ # so this is an Aegis invocation; pass the test (exit 0).
+ self.pass_test()
+
+# Local Variables:
+# tab-width:4
+# indent-tabs-mode:nil
+# End:
+# vim: set expandtab tabstop=4 shiftwidth=4:
diff --git a/Source/ThirdParty/gyp/test/lib/TestGyp.py b/Source/ThirdParty/gyp/test/lib/TestGyp.py
new file mode 100644
index 000000000..23228d2fa
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/lib/TestGyp.py
@@ -0,0 +1,724 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+TestGyp.py: a testing framework for GYP integration tests.
+"""
+
+import os
+import re
+import shutil
+import stat
+import sys
+
+import TestCommon
+from TestCommon import __all__
+
+__all__.extend([
+ 'TestGyp',
+])
+
+
+class TestGypBase(TestCommon.TestCommon):
+ """
+ Class for controlling end-to-end tests of gyp generators.
+
+ Instantiating this class will create a temporary directory and
+ arrange for its destruction (via the TestCmd superclass) and
+ copy all of the non-gyptest files in the directory hierarchy of the
+ executing script.
+
+ The default behavior is to test the 'gyp' or 'gyp.bat' file in the
+ current directory. An alternative may be specified explicitly on
+ instantiation, or by setting the TESTGYP_GYP environment variable.
+
+ This class should be subclassed for each supported gyp generator
+ (format). Various abstract methods below define calling signatures
+ used by the test scripts to invoke builds on the generated build
+ configuration and to run executables generated by those builds.
+ """
+
+ build_tool = None
+ build_tool_list = []
+
+ _exe = TestCommon.exe_suffix
+ _obj = TestCommon.obj_suffix
+ shobj_ = TestCommon.shobj_prefix
+ _shobj = TestCommon.shobj_suffix
+ lib_ = TestCommon.lib_prefix
+ _lib = TestCommon.lib_suffix
+ dll_ = TestCommon.dll_prefix
+ _dll = TestCommon.dll_suffix
+
+ # Constants to represent different targets.
+ ALL = '__all__'
+ DEFAULT = '__default__'
+
+ # Constants for different target types.
+ EXECUTABLE = '__executable__'
+ STATIC_LIB = '__static_lib__'
+ SHARED_LIB = '__shared_lib__'
+
+ def __init__(self, gyp=None, *args, **kw):
+ self.origin_cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
+
+ if not gyp:
+ gyp = os.environ.get('TESTGYP_GYP')
+ if not gyp:
+ if sys.platform == 'win32':
+ gyp = 'gyp.bat'
+ else:
+ gyp = 'gyp'
+ self.gyp = os.path.abspath(gyp)
+
+ self.initialize_build_tool()
+
+ if not kw.has_key('match'):
+ kw['match'] = TestCommon.match_exact
+
+ if not kw.has_key('workdir'):
+ # Default behavior: the null string causes TestCmd to create
+ # a temporary directory for us.
+ kw['workdir'] = ''
+
+ formats = kw.get('formats', [])
+ if kw.has_key('formats'):
+ del kw['formats']
+
+ super(TestGypBase, self).__init__(*args, **kw)
+
+ excluded_formats = set([f for f in formats if f[0] == '!'])
+ included_formats = set(formats) - excluded_formats
+ if ('!'+self.format in excluded_formats or
+ included_formats and self.format not in included_formats):
+ msg = 'Invalid test for %r format; skipping test.\n'
+ self.skip_test(msg % self.format)
+
+ self.copy_test_configuration(self.origin_cwd, self.workdir)
+ self.set_configuration(None)
+
+ def built_file_must_exist(self, name, type=None, **kw):
+ """
+ Fails the test if the specified built file name does not exist.
+ """
+ return self.must_exist(self.built_file_path(name, type, **kw))
+
+ def built_file_must_not_exist(self, name, type=None, **kw):
+ """
+ Fails the test if the specified built file name exists.
+ """
+ return self.must_not_exist(self.built_file_path(name, type, **kw))
+
+ def built_file_must_match(self, name, contents, **kw):
+ """
+ Fails the test if the contents of the specified built file name
+ do not match the specified contents.
+ """
+ return self.must_match(self.built_file_path(name, **kw), contents)
+
+ def built_file_must_not_match(self, name, contents, **kw):
+ """
+ Fails the test if the contents of the specified built file name
+ match the specified contents.
+ """
+ return self.must_not_match(self.built_file_path(name, **kw), contents)
+
+ def copy_test_configuration(self, source_dir, dest_dir):
+ """
+ Copies the test configuration from the specified source_dir
+ (the directory in which the test script lives) to the
+ specified dest_dir (a temporary working directory).
+
+ This ignores all files and directories that begin with
+ the string 'gyptest', and all '.svn' subdirectories.
+ """
+ for root, dirs, files in os.walk(source_dir):
+ if '.svn' in dirs:
+ dirs.remove('.svn')
+ dirs = [ d for d in dirs if not d.startswith('gyptest') ]
+ files = [ f for f in files if not f.startswith('gyptest') ]
+ for dirname in dirs:
+ source = os.path.join(root, dirname)
+ destination = source.replace(source_dir, dest_dir)
+ os.mkdir(destination)
+ if sys.platform != 'win32':
+ shutil.copystat(source, destination)
+ for filename in files:
+ source = os.path.join(root, filename)
+ destination = source.replace(source_dir, dest_dir)
+ shutil.copy2(source, destination)
+
+ def initialize_build_tool(self):
+ """
+ Initializes the .build_tool attribute.
+
+ Searches the .build_tool_list for an executable name on the user's
+ $PATH. The first tool on the list is used as-is if nothing is found
+ on the current $PATH.
+ """
+ for build_tool in self.build_tool_list:
+ if not build_tool:
+ continue
+ if os.path.isabs(build_tool):
+ self.build_tool = build_tool
+ return
+ build_tool = self.where_is(build_tool)
+ if build_tool:
+ self.build_tool = build_tool
+ return
+
+ if self.build_tool_list:
+ self.build_tool = self.build_tool_list[0]
+
+ def relocate(self, source, destination):
+ """
+ Renames (relocates) the specified source (usually a directory)
+ to the specified destination, creating the destination directory
+ first if necessary.
+
+ Note: Don't use this as a generic "rename" operation. In the
+ future, "relocating" parts of a GYP tree may affect the state of
+ the test to modify the behavior of later method calls.
+ """
+ destination_dir = os.path.dirname(destination)
+ if not os.path.exists(destination_dir):
+ self.subdir(destination_dir)
+ os.rename(source, destination)
+
+ def report_not_up_to_date(self):
+ """
+ Reports that a build is not up-to-date.
+
+ This provides common reporting for formats that have complicated
+ conditions for checking whether a build is up-to-date. Formats
+ that expect exact output from the command (make, scons) can
+ just set stdout= when they call the run_build() method.
+ """
+ print "Build is not up-to-date:"
+ print self.banner('STDOUT ')
+ print self.stdout()
+ stderr = self.stderr()
+ if stderr:
+ print self.banner('STDERR ')
+ print stderr
+
+ def run_gyp(self, gyp_file, *args, **kw):
+ """
+ Runs gyp against the specified gyp_file with the specified args.
+ """
+ # TODO: --depth=. works around Chromium-specific tree climbing.
+ args = ('--depth=.', '--format='+self.format, gyp_file) + args
+ return self.run(program=self.gyp, arguments=args, **kw)
+
+ def run(self, *args, **kw):
+ """
+ Executes a program by calling the superclass .run() method.
+
+ This exists to provide a common place to filter out keyword
+ arguments implemented in this layer, without having to update
+ the tool-specific subclasses or clutter the tests themselves
+ with platform-specific code.
+ """
+ if kw.has_key('SYMROOT'):
+ del kw['SYMROOT']
+ super(TestGypBase, self).run(*args, **kw)
+
+ def set_configuration(self, configuration):
+ """
+ Sets the configuration, to be used for invoking the build
+ tool and testing potential built output.
+ """
+ self.configuration = configuration
+
+ def configuration_dirname(self):
+ if self.configuration:
+ return self.configuration.split('|')[0]
+ else:
+ return 'Default'
+
+ def configuration_buildname(self):
+ if self.configuration:
+ return self.configuration
+ else:
+ return 'Default'
+
+ #
+ # Abstract methods to be defined by format-specific subclasses.
+ #
+
+ def build(self, gyp_file, target=None, **kw):
+ """
+ Runs a build of the specified target against the configuration
+ generated from the specified gyp_file.
+
+ A 'target' argument of None or the special value TestGyp.DEFAULT
+ specifies the default argument for the underlying build tool.
+ A 'target' argument of TestGyp.ALL specifies the 'all' target
+ (if any) of the underlying build tool.
+ """
+ raise NotImplementedError
+
+ def built_file_path(self, name, type=None, **kw):
+ """
+ Returns a path to the specified file name, of the specified type.
+ """
+ raise NotImplementedError
+
+ def built_file_basename(self, name, type=None, **kw):
+ """
+ Returns the base name of the specified file name, of the specified type.
+
+ A bare=True keyword argument specifies that prefixes and suffixes shouldn't
+ be applied.
+ """
+ if not kw.get('bare'):
+ if type == self.EXECUTABLE:
+ name = name + self._exe
+ elif type == self.STATIC_LIB:
+ name = self.lib_ + name + self._lib
+ elif type == self.SHARED_LIB:
+ name = self.dll_ + name + self._dll
+ return name
+
+ def run_built_executable(self, name, *args, **kw):
+ """
+ Runs an executable program built from a gyp-generated configuration.
+
+ The specified name should be independent of any particular generator.
+ Subclasses should find the output executable in the appropriate
+ output build directory, tack on any necessary executable suffix, etc.
+ """
+ raise NotImplementedError
+
+ def up_to_date(self, gyp_file, target=None, **kw):
+ """
+ Verifies that a build of the specified target is up to date.
+
+ The subclass should implement this by calling build()
+ (or a reasonable equivalent), checking whatever conditions
+ will tell it the build was an "up to date" null build, and
+ failing if it isn't.
+ """
+ raise NotImplementedError
+
+
+class TestGypGypd(TestGypBase):
+ """
+ Subclass for testing the GYP 'gypd' generator (spit out the
+ internal data structure as pretty-printed Python).
+ """
+ format = 'gypd'
+
+
+class TestGypMake(TestGypBase):
+ """
+ Subclass for testing the GYP Make generator.
+ """
+ format = 'make'
+ build_tool_list = ['make']
+ ALL = 'all'
+ def build(self, gyp_file, target=None, **kw):
+ """
+ Runs a Make build using the Makefiles generated from the specified
+ gyp_file.
+ """
+ arguments = kw.get('arguments', [])[:]
+ if self.configuration:
+ arguments.append('BUILDTYPE=' + self.configuration)
+ if target not in (None, self.DEFAULT):
+ arguments.append(target)
+ # Sub-directory builds provide per-gyp Makefiles (i.e.
+ # Makefile.gyp_filename), so use that if there is no Makefile.
+ chdir = kw.get('chdir', '')
+ if not os.path.exists(os.path.join(chdir, 'Makefile')):
+ print "NO Makefile in " + os.path.join(chdir, 'Makefile')
+ arguments.insert(0, '-f')
+ arguments.insert(1, os.path.splitext(gyp_file)[0] + '.Makefile')
+ kw['arguments'] = arguments
+ return self.run(program=self.build_tool, **kw)
+ def up_to_date(self, gyp_file, target=None, **kw):
+ """
+ Verifies that a build of the specified Make target is up to date.
+ """
+ if target in (None, self.DEFAULT):
+ message_target = 'all'
+ else:
+ message_target = target
+ kw['stdout'] = "make: Nothing to be done for `%s'.\n" % message_target
+ return self.build(gyp_file, target, **kw)
+ def run_built_executable(self, name, *args, **kw):
+ """
+ Runs an executable built by Make.
+ """
+ configuration = self.configuration_dirname()
+ libdir = os.path.join('out', configuration, 'lib')
+ # TODO(piman): when everything is cross-compile safe, remove lib.target
+ os.environ['LD_LIBRARY_PATH'] = libdir + '.host:' + libdir + '.target'
+ # Enclosing the name in a list avoids prepending the original dir.
+ program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+ return self.run(program=program, *args, **kw)
+ def built_file_path(self, name, type=None, **kw):
+ """
+ Returns a path to the specified file name, of the specified type,
+ as built by Make.
+
+ Built files are in the subdirectory 'out/{configuration}'.
+ The default is 'out/Default'.
+
+ A chdir= keyword argument specifies the source directory
+ relative to which the output subdirectory can be found.
+
+ "type" values of STATIC_LIB or SHARED_LIB append the necessary
+ prefixes and suffixes to a platform-independent library base name.
+
+ A libdir= keyword argument specifies a library subdirectory other
+ than the default 'obj.target'.
+ """
+ result = []
+ chdir = kw.get('chdir')
+ if chdir:
+ result.append(chdir)
+ configuration = self.configuration_dirname()
+ result.extend(['out', configuration])
+ if type == self.STATIC_LIB:
+ result.append(kw.get('libdir', 'obj.target'))
+ elif type == self.SHARED_LIB:
+ result.append(kw.get('libdir', 'lib.target'))
+ result.append(self.built_file_basename(name, type, **kw))
+ return self.workpath(*result)
+
+
+class TestGypMSVS(TestGypBase):
+ """
+ Subclass for testing the GYP Visual Studio generator.
+ """
+ format = 'msvs'
+
+ u = r'=== Build: (\d+) succeeded, 0 failed, (\d+) up-to-date, 0 skipped ==='
+ up_to_date_re = re.compile(u, re.M)
+
+ # Initial None element will indicate to our .initialize_build_tool()
+ # method below that 'devenv' was not found on %PATH%.
+ #
+ # Note: we must use devenv.com to be able to capture build output.
+ # Directly executing devenv.exe only sends output to BuildLog.htm.
+ build_tool_list = [None, 'devenv.com']
+
+ def initialize_build_tool(self):
+ """ Initializes the Visual Studio .build_tool and .uses_msbuild parameters.
+
+ We use the value specified by GYP_MSVS_VERSION. If not specified, we
+ search %PATH% and %PATHEXT% for a devenv.{exe,bat,...} executable.
+ Failing that, we search for likely deployment paths.
+ """
+ super(TestGypMSVS, self).initialize_build_tool()
+ possible_roots = ['C:\\Program Files (x86)', 'C:\\Program Files']
+ possible_paths = {
+ '2010': r'Microsoft Visual Studio 10.0\Common7\IDE\devenv.com',
+ '2008': r'Microsoft Visual Studio 9.0\Common7\IDE\devenv.com',
+ '2005': r'Microsoft Visual Studio 8\Common7\IDE\devenv.com'}
+ msvs_version = os.environ.get('GYP_MSVS_VERSION', 'auto')
+ if msvs_version in possible_paths:
+ # Check that the path to the specified GYP_MSVS_VERSION exists.
+ path = possible_paths[msvs_version]
+ for r in possible_roots:
+ bt = os.path.join(r, path)
+ if os.path.exists(bt):
+ self.build_tool = bt
+ self.uses_msbuild = msvs_version >= '2010'
+ return
+ else:
+ print ('Warning: Environment variable GYP_MSVS_VERSION specifies "%s" '
+ 'but corresponding "%s" was not found.' % (msvs_version, path))
+ if self.build_tool:
+ # We found 'devenv' on the path, use that and try to guess the version.
+ for version, path in possible_paths.iteritems():
+ if self.build_tool.find(path) >= 0:
+ self.uses_msbuild = version >= '2010'
+ return
+ else:
+ # If not, assume not MSBuild.
+ self.uses_msbuild = False
+ return
+ # Neither GYP_MSVS_VERSION nor the path help us out. Iterate through
+ # the choices looking for a match.
+ for version, path in possible_paths.iteritems():
+ for r in possible_roots:
+ bt = os.path.join(r, path)
+ if os.path.exists(bt):
+ self.build_tool = bt
+ self.uses_msbuild = msvs_version >= '2010'
+ return
+ print 'Error: could not find devenv'
+ sys.exit(1)
+ def build(self, gyp_file, target=None, rebuild=False, **kw):
+ """
+ Runs a Visual Studio build using the configuration generated
+ from the specified gyp_file.
+ """
+ configuration = self.configuration_buildname()
+ if rebuild:
+ build = '/Rebuild'
+ else:
+ build = '/Build'
+ arguments = kw.get('arguments', [])[:]
+ arguments.extend([gyp_file.replace('.gyp', '.sln'),
+ build, configuration])
+ # Note: the Visual Studio generator doesn't add an explicit 'all'
+ # target, so we just treat it the same as the default.
+ if target not in (None, self.ALL, self.DEFAULT):
+ arguments.extend(['/Project', target])
+ if self.configuration:
+ arguments.extend(['/ProjectConfig', self.configuration])
+ kw['arguments'] = arguments
+ return self.run(program=self.build_tool, **kw)
+ def up_to_date(self, gyp_file, target=None, **kw):
+ """
+ Verifies that a build of the specified Visual Studio target is up to date.
+ """
+ result = self.build(gyp_file, target, **kw)
+ if not result:
+ stdout = self.stdout()
+ m = self.up_to_date_re.search(stdout)
+ up_to_date = False
+ if m:
+ succeeded = m.group(1)
+ up_to_date = m.group(2)
+ up_to_date = succeeded == '0' and up_to_date == '1'
+ # Figuring out if the build is up to date changed with VS2010.
+ # For builds that should be up to date, I sometimes get
+ # "1 succeeded and 0 up to date". As an ad-hoc measure, we check
+ # this and also verify that th number of output lines is small.
+ # I don't know if this is caused by VS itself or is due to
+ # interaction with virus checkers.
+ if self.uses_msbuild and (succeeded == '1' and
+ up_to_date == '0' and
+ stdout.count('\n') <= 6):
+ up_to_date = True
+ if not up_to_date:
+ self.report_not_up_to_date()
+ self.fail_test()
+ return result
+ def run_built_executable(self, name, *args, **kw):
+ """
+ Runs an executable built by Visual Studio.
+ """
+ configuration = self.configuration_dirname()
+ # Enclosing the name in a list avoids prepending the original dir.
+ program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+ return self.run(program=program, *args, **kw)
+ def built_file_path(self, name, type=None, **kw):
+ """
+ Returns a path to the specified file name, of the specified type,
+ as built by Visual Studio.
+
+ Built files are in a subdirectory that matches the configuration
+ name. The default is 'Default'.
+
+ A chdir= keyword argument specifies the source directory
+ relative to which the output subdirectory can be found.
+
+ "type" values of STATIC_LIB or SHARED_LIB append the necessary
+ prefixes and suffixes to a platform-independent library base name.
+ """
+ result = []
+ chdir = kw.get('chdir')
+ if chdir:
+ result.append(chdir)
+ result.append(self.configuration_dirname())
+ if type == self.STATIC_LIB:
+ result.append('lib')
+ result.append(self.built_file_basename(name, type, **kw))
+ return self.workpath(*result)
+
+
+class TestGypSCons(TestGypBase):
+ """
+ Subclass for testing the GYP SCons generator.
+ """
+ format = 'scons'
+ build_tool_list = ['scons', 'scons.py']
+ ALL = 'all'
+ def build(self, gyp_file, target=None, **kw):
+ """
+ Runs a scons build using the SCons configuration generated from the
+ specified gyp_file.
+ """
+ arguments = kw.get('arguments', [])[:]
+ dirname = os.path.dirname(gyp_file)
+ if dirname:
+ arguments.extend(['-C', dirname])
+ if self.configuration:
+ arguments.append('--mode=' + self.configuration)
+ if target not in (None, self.DEFAULT):
+ arguments.append(target)
+ kw['arguments'] = arguments
+ return self.run(program=self.build_tool, **kw)
+ def up_to_date(self, gyp_file, target=None, **kw):
+ """
+ Verifies that a build of the specified SCons target is up to date.
+ """
+ if target in (None, self.DEFAULT):
+ up_to_date_targets = 'all'
+ else:
+ up_to_date_targets = target
+ up_to_date_lines = []
+ for arg in up_to_date_targets.split():
+ up_to_date_lines.append("scons: `%s' is up to date.\n" % arg)
+ kw['stdout'] = ''.join(up_to_date_lines)
+ arguments = kw.get('arguments', [])[:]
+ arguments.append('-Q')
+ kw['arguments'] = arguments
+ return self.build(gyp_file, target, **kw)
+ def run_built_executable(self, name, *args, **kw):
+ """
+ Runs an executable built by scons.
+ """
+ configuration = self.configuration_dirname()
+ os.environ['LD_LIBRARY_PATH'] = os.path.join(configuration, 'lib')
+ # Enclosing the name in a list avoids prepending the original dir.
+ program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+ return self.run(program=program, *args, **kw)
+ def built_file_path(self, name, type=None, **kw):
+ """
+ Returns a path to the specified file name, of the specified type,
+ as built by Scons.
+
+ Built files are in a subdirectory that matches the configuration
+ name. The default is 'Default'.
+
+ A chdir= keyword argument specifies the source directory
+ relative to which the output subdirectory can be found.
+
+ "type" values of STATIC_LIB or SHARED_LIB append the necessary
+ prefixes and suffixes to a platform-independent library base name.
+ """
+ result = []
+ chdir = kw.get('chdir')
+ if chdir:
+ result.append(chdir)
+ result.append(self.configuration_dirname())
+ if type in (self.STATIC_LIB, self.SHARED_LIB):
+ result.append('lib')
+ result.append(self.built_file_basename(name, type, **kw))
+ return self.workpath(*result)
+
+
+class TestGypXcode(TestGypBase):
+ """
+ Subclass for testing the GYP Xcode generator.
+ """
+ format = 'xcode'
+ build_tool_list = ['xcodebuild']
+
+ phase_script_execution = ("\n"
+ "PhaseScriptExecution /\\S+/Script-[0-9A-F]+\\.sh\n"
+ " cd /\\S+\n"
+ " /bin/sh -c /\\S+/Script-[0-9A-F]+\\.sh\n"
+ "(make: Nothing to be done for `all'\\.\n)?")
+
+ strip_up_to_date_expressions = [
+ # Various actions or rules can run even when the overall build target
+ # is up to date. Strip those phases' GYP-generated output.
+ re.compile(phase_script_execution, re.S),
+
+ # The message from distcc_pump can trail the "BUILD SUCCEEDED"
+ # message, so strip that, too.
+ re.compile('__________Shutting down distcc-pump include server\n', re.S),
+ ]
+
+ up_to_date_endings = (
+ 'Checking Dependencies...\n** BUILD SUCCEEDED **\n', # Xcode 3.0/3.1
+ 'Check dependencies\n** BUILD SUCCEEDED **\n\n', # Xcode 3.2
+ )
+
+ def build(self, gyp_file, target=None, **kw):
+ """
+ Runs an xcodebuild using the .xcodeproj generated from the specified
+ gyp_file.
+ """
+ # Be sure we're working with a copy of 'arguments' since we modify it.
+ # The caller may not be expecting it to be modified.
+ arguments = kw.get('arguments', [])[:]
+ arguments.extend(['-project', gyp_file.replace('.gyp', '.xcodeproj')])
+ if target == self.ALL:
+ arguments.append('-alltargets',)
+ elif target not in (None, self.DEFAULT):
+ arguments.extend(['-target', target])
+ if self.configuration:
+ arguments.extend(['-configuration', self.configuration])
+ symroot = kw.get('SYMROOT', '$SRCROOT/build')
+ if symroot:
+ arguments.append('SYMROOT='+symroot)
+ kw['arguments'] = arguments
+ return self.run(program=self.build_tool, **kw)
+ def up_to_date(self, gyp_file, target=None, **kw):
+ """
+ Verifies that a build of the specified Xcode target is up to date.
+ """
+ result = self.build(gyp_file, target, **kw)
+ if not result:
+ output = self.stdout()
+ for expression in self.strip_up_to_date_expressions:
+ output = expression.sub('', output)
+ if not output.endswith(self.up_to_date_endings):
+ self.report_not_up_to_date()
+ self.fail_test()
+ return result
+ def run_built_executable(self, name, *args, **kw):
+ """
+ Runs an executable built by xcodebuild.
+ """
+ configuration = self.configuration_dirname()
+ os.environ['DYLD_LIBRARY_PATH'] = os.path.join('build', configuration)
+ # Enclosing the name in a list avoids prepending the original dir.
+ program = [self.built_file_path(name, type=self.EXECUTABLE, **kw)]
+ return self.run(program=program, *args, **kw)
+ def built_file_path(self, name, type=None, **kw):
+ """
+ Returns a path to the specified file name, of the specified type,
+ as built by Xcode.
+
+ Built files are in the subdirectory 'build/{configuration}'.
+ The default is 'build/Default'.
+
+ A chdir= keyword argument specifies the source directory
+ relative to which the output subdirectory can be found.
+
+ "type" values of STATIC_LIB or SHARED_LIB append the necessary
+ prefixes and suffixes to a platform-independent library base name.
+ """
+ result = []
+ chdir = kw.get('chdir')
+ if chdir:
+ result.append(chdir)
+ configuration = self.configuration_dirname()
+ result.extend(['build', configuration])
+ result.append(self.built_file_basename(name, type, **kw))
+ return self.workpath(*result)
+
+
+format_class_list = [
+ TestGypGypd,
+ TestGypMake,
+ TestGypMSVS,
+ TestGypSCons,
+ TestGypXcode,
+]
+
+def TestGyp(*args, **kw):
+ """
+ Returns an appropriate TestGyp* instance for a specified GYP format.
+ """
+ format = kw.get('format')
+ if format:
+ del kw['format']
+ else:
+ format = os.environ.get('TESTGYP_FORMAT')
+ for format_class in format_class_list:
+ if format == format_class.format:
+ return format_class(*args, **kw)
+ raise Exception, "unknown format %r" % format
diff --git a/Source/ThirdParty/gyp/test/library/gyptest-shared-obj-install-path.py b/Source/ThirdParty/gyp/test/library/gyptest-shared-obj-install-path.py
new file mode 100644
index 000000000..2cf1a2845
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/gyptest-shared-obj-install-path.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that .so files that are order only dependencies are specified by
+their install location rather than by their alias.
+"""
+
+# Python 2.5 needs this for the with statement.
+from __future__ import with_statement
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('shared_dependency.gyp',
+ chdir='src')
+test.relocate('src', 'relocate/src')
+
+test.build('shared_dependency.gyp', test.ALL, chdir='relocate/src')
+
+with open('relocate/src/Makefile') as makefile:
+ make_contents = makefile.read()
+
+# If we remove the code to generate lib1, Make should still be able
+# to build lib2 since lib1.so already exists.
+make_contents = make_contents.replace('include lib1.target.mk', '')
+with open('relocate/src/Makefile', 'w') as makefile:
+ makefile.write(make_contents)
+
+test.build('shared_dependency.gyp', test.ALL, chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/library/gyptest-shared.py b/Source/ThirdParty/gyp/test/library/gyptest-shared.py
new file mode 100644
index 000000000..a1d2985d9
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/gyptest-shared.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple build of a "Hello, world!" program with shared libraries,
+including verifying that libraries are rebuilt correctly when functions
+move between libraries.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('library.gyp',
+ '-Dlibrary=shared_library',
+ '-Dmoveable_function=lib1',
+ chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib1_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.run_gyp('library.gyp',
+ '-Dlibrary=shared_library',
+ '-Dmoveable_function=lib2',
+ chdir='relocate/src')
+
+# Update program.c to force a rebuild.
+test.sleep()
+contents = test.read('relocate/src/program.c')
+contents = contents.replace('Hello', 'Hello again')
+test.write('relocate/src/program.c', contents)
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello again from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib2_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.run_gyp('library.gyp',
+ '-Dlibrary=shared_library',
+ '-Dmoveable_function=lib1',
+ chdir='relocate/src')
+
+# Update program.c to force a rebuild.
+test.sleep()
+contents = test.read('relocate/src/program.c')
+contents = contents.replace('again', 'again again')
+test.write('relocate/src/program.c', contents)
+
+# TODO(sgk): we have to force a rebuild of lib2 so that it weeds out
+# the "moved" module. This should be done in gyp by adding a dependency
+# on the generated .vcproj file itself.
+test.touch('relocate/src/lib2.c')
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello again again from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib1_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/library/gyptest-static.py b/Source/ThirdParty/gyp/test/library/gyptest-static.py
new file mode 100644
index 000000000..4bc71c496
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/gyptest-static.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple build of a "Hello, world!" program with static libraries,
+including verifying that libraries are rebuilt correctly when functions
+move between libraries.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('library.gyp',
+ '-Dlibrary=static_library',
+ '-Dmoveable_function=lib1',
+ chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib1_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.run_gyp('library.gyp',
+ '-Dlibrary=static_library',
+ '-Dmoveable_function=lib2',
+ chdir='relocate/src')
+
+# Update program.c to force a rebuild.
+test.sleep()
+contents = test.read('relocate/src/program.c')
+contents = contents.replace('Hello', 'Hello again')
+test.write('relocate/src/program.c', contents)
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello again from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib2_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.run_gyp('library.gyp',
+ '-Dlibrary=static_library',
+ '-Dmoveable_function=lib1',
+ chdir='relocate/src')
+
+# Update program.c and lib2.c to force a rebuild.
+test.sleep()
+contents = test.read('relocate/src/program.c')
+contents = contents.replace('again', 'again again')
+test.write('relocate/src/program.c', contents)
+
+# TODO(sgk): we have to force a rebuild of lib2 so that it weeds out
+# the "moved" module. This should be done in gyp by adding a dependency
+# on the generated .vcproj file itself.
+test.touch('relocate/src/lib2.c')
+
+test.build('library.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello again again from program.c
+Hello from lib1.c
+Hello from lib2.c
+Hello from lib1_moveable.c
+"""
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/library/src/lib1.c b/Source/ThirdParty/gyp/test/library/src/lib1.c
new file mode 100644
index 000000000..3866b1b84
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/src/lib1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void lib1_function(void)
+{
+ fprintf(stdout, "Hello from lib1.c\n");
+ fflush(stdout);
+}
diff --git a/Source/ThirdParty/gyp/test/library/src/lib1_moveable.c b/Source/ThirdParty/gyp/test/library/src/lib1_moveable.c
new file mode 100644
index 000000000..5d3cc1d9a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/src/lib1_moveable.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void moveable_function(void)
+{
+ fprintf(stdout, "Hello from lib1_moveable.c\n");
+ fflush(stdout);
+}
diff --git a/Source/ThirdParty/gyp/test/library/src/lib2.c b/Source/ThirdParty/gyp/test/library/src/lib2.c
new file mode 100644
index 000000000..21dda7265
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/src/lib2.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void lib2_function(void)
+{
+ fprintf(stdout, "Hello from lib2.c\n");
+ fflush(stdout);
+}
diff --git a/Source/ThirdParty/gyp/test/library/src/lib2_moveable.c b/Source/ThirdParty/gyp/test/library/src/lib2_moveable.c
new file mode 100644
index 000000000..f645071d1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/src/lib2_moveable.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void moveable_function(void)
+{
+ fprintf(stdout, "Hello from lib2_moveable.c\n");
+ fflush(stdout);
+}
diff --git a/Source/ThirdParty/gyp/test/library/src/library.gyp b/Source/ThirdParty/gyp/test/library/src/library.gyp
new file mode 100644
index 000000000..51f59bc45
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/src/library.gyp
@@ -0,0 +1,58 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'moveable_function%': 0,
+ },
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'dependencies': [
+ 'lib1',
+ 'lib2',
+ ],
+ 'sources': [
+ 'program.c',
+ ],
+ },
+ {
+ 'target_name': 'lib1',
+ 'type': 'static_library',
+ 'sources': [
+ 'lib1.c',
+ ],
+ 'conditions': [
+ ['moveable_function=="lib1"', {
+ 'sources': [
+ 'lib1_moveable.c',
+ ],
+ }],
+ ],
+ },
+ {
+ 'target_name': 'lib2',
+ 'type': 'static_library',
+ 'sources': [
+ 'lib2.c',
+ ],
+ 'conditions': [
+ ['moveable_function=="lib2"', {
+ 'sources': [
+ 'lib2_moveable.c',
+ ],
+ }],
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'target_defaults': {
+ # Support 64-bit shared libs (also works fine for 32-bit).
+ 'cflags': ['-fPIC'],
+ },
+ }],
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/library/src/program.c b/Source/ThirdParty/gyp/test/library/src/program.c
new file mode 100644
index 000000000..d7712cced
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/src/program.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+extern void lib1_function(void);
+extern void lib2_function(void);
+extern void moveable_function(void);
+
+int main(int argc, char *argv[])
+{
+ fprintf(stdout, "Hello from program.c\n");
+ fflush(stdout);
+ lib1_function();
+ lib2_function();
+ moveable_function();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/library/src/shared_dependency.gyp b/Source/ThirdParty/gyp/test/library/src/shared_dependency.gyp
new file mode 100644
index 000000000..7d29f5de5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/library/src/shared_dependency.gyp
@@ -0,0 +1,33 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'lib1',
+ 'type': 'shared_library',
+ 'sources': [
+ 'lib1.c',
+ ],
+ },
+ {
+ 'target_name': 'lib2',
+ 'type': 'shared_library',
+ 'sources': [
+ 'lib2.c',
+ ],
+ 'dependencies': [
+ 'lib1',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'target_defaults': {
+ # Support 64-bit shared libs (also works fine for 32-bit).
+ 'cflags': ['-fPIC'],
+ },
+ }],
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/link-objects/base.c b/Source/ThirdParty/gyp/test/link-objects/base.c
new file mode 100644
index 000000000..2bc29a1b1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/link-objects/base.c
@@ -0,0 +1,6 @@
+void extra();
+
+int main(int argc, char** argv) {
+ extra();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/link-objects/extra.c b/Source/ThirdParty/gyp/test/link-objects/extra.c
new file mode 100644
index 000000000..1d7ee09b1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/link-objects/extra.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+void extra() {
+ printf("PASS\n");
+}
diff --git a/Source/ThirdParty/gyp/test/link-objects/gyptest-all.py b/Source/ThirdParty/gyp/test/link-objects/gyptest-all.py
new file mode 100644
index 000000000..b58a3963d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/link-objects/gyptest-all.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Put an object file on the sources list.
+Expect the result to link ok.
+"""
+
+import TestGyp
+
+# Currently only works under the make build.
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('link-objects.gyp')
+
+test.build('link-objects.gyp', test.ALL)
+
+test.run_built_executable('link-objects', stdout="PASS\n")
+
+test.up_to_date('link-objects.gyp', test.ALL)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/link-objects/link-objects.gyp b/Source/ThirdParty/gyp/test/link-objects/link-objects.gyp
new file mode 100644
index 000000000..ab7285553
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/link-objects/link-objects.gyp
@@ -0,0 +1,24 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'link-objects',
+ 'type': 'executable',
+ 'actions': [
+ {
+ 'action_name': 'build extra object',
+ 'inputs': ['extra.c'],
+ 'outputs': ['extra.o'],
+ 'action': ['gcc', '-o', 'extra.o', '-c', 'extra.c'],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ 'sources': [
+ 'base.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/make/dependencies.gyp b/Source/ThirdParty/gyp/test/make/dependencies.gyp
new file mode 100644
index 000000000..e2bee24fc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/dependencies.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'main',
+ 'type': 'executable',
+ 'sources': [
+ 'main.cc',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/make/gyptest-dependencies.py b/Source/ThirdParty/gyp/test/make/gyptest-dependencies.py
new file mode 100644
index 000000000..76cfd0e81
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/gyptest-dependencies.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that .d files and all.deps are properly generated.
+"""
+
+import os
+import TestGyp
+
+# .d files are only used by the make build.
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('dependencies.gyp')
+
+test.build('dependencies.gyp', test.ALL)
+
+deps_file = test.built_file_path(".deps/out/Default/obj.target/main/main.o.d")
+test.must_contain(deps_file, "main.h")
+
+# Build a second time to make sure we generate all.deps.
+test.build('dependencies.gyp', test.ALL)
+
+all_deps_file = test.built_file_path(".deps/all.deps")
+test.must_contain(all_deps_file, "main.h")
+test.must_contain(all_deps_file, "cmd_")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/make/gyptest-noload.py b/Source/ThirdParty/gyp/test/make/gyptest-noload.py
new file mode 100644
index 000000000..1f5103315
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/gyptest-noload.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Tests the use of the NO_LOAD flag which makes loading sub .mk files
+optional.
+"""
+
+# Python 2.5 needs this for the with statement.
+from __future__ import with_statement
+
+import os
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('all.gyp', chdir='noload')
+
+test.relocate('noload', 'relocate/noload')
+
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload')
+test.run_built_executable('exe', chdir='relocate/noload',
+ stdout='Hello from shared.c.\n')
+
+# Just sanity test that NO_LOAD=lib doesn't break anything.
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload',
+ arguments=['NO_LOAD=lib'])
+test.run_built_executable('exe', chdir='relocate/noload',
+ stdout='Hello from shared.c.\n')
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload',
+ arguments=['NO_LOAD=z'])
+test.run_built_executable('exe', chdir='relocate/noload',
+ stdout='Hello from shared.c.\n')
+
+# Make sure we can rebuild without reloading the sub .mk file.
+with open('relocate/noload/main.c', 'a') as src_file:
+ src_file.write("\n")
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload',
+ arguments=['NO_LOAD=lib'])
+test.run_built_executable('exe', chdir='relocate/noload',
+ stdout='Hello from shared.c.\n')
+
+# Change shared.c, but verify that it doesn't get rebuild if we don't load it.
+with open('relocate/noload/lib/shared.c', 'w') as shared_file:
+ shared_file.write(
+ '#include "shared.h"\n'
+ 'const char kSharedStr[] = "modified";\n'
+ )
+test.build('build/all.gyp', test.ALL, chdir='relocate/noload',
+ arguments=['NO_LOAD=lib'])
+test.run_built_executable('exe', chdir='relocate/noload',
+ stdout='Hello from shared.c.\n')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/make/main.cc b/Source/ThirdParty/gyp/test/make/main.cc
new file mode 100644
index 000000000..70ac6e46a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/main.cc
@@ -0,0 +1,12 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+#include "main.h"
+
+int main(int argc, char *argv[]) {
+ printf("hello world\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/make/main.h b/Source/ThirdParty/gyp/test/make/main.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/main.h
diff --git a/Source/ThirdParty/gyp/test/make/noload/all.gyp b/Source/ThirdParty/gyp/test/make/noload/all.gyp
new file mode 100644
index 000000000..1617a9e97
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/noload/all.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'exe',
+ 'type': 'executable',
+ 'sources': [
+ 'main.c',
+ ],
+ 'dependencies': [
+ 'lib/shared.gyp:shared',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/make/noload/lib/shared.c b/Source/ThirdParty/gyp/test/make/noload/lib/shared.c
new file mode 100644
index 000000000..51776c5ac
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/noload/lib/shared.c
@@ -0,0 +1,3 @@
+#include "shared.h"
+
+const char kSharedStr[] = "shared.c";
diff --git a/Source/ThirdParty/gyp/test/make/noload/lib/shared.gyp b/Source/ThirdParty/gyp/test/make/noload/lib/shared.gyp
new file mode 100644
index 000000000..8a8841b3a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/noload/lib/shared.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'shared',
+ 'type': 'shared_library',
+ 'sources': [
+ 'shared.c',
+ 'shared.h',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/make/noload/lib/shared.h b/Source/ThirdParty/gyp/test/make/noload/lib/shared.h
new file mode 100644
index 000000000..a21da7538
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/noload/lib/shared.h
@@ -0,0 +1 @@
+extern const char kSharedStr[];
diff --git a/Source/ThirdParty/gyp/test/make/noload/main.c b/Source/ThirdParty/gyp/test/make/noload/main.c
new file mode 100644
index 000000000..46d3c52c2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/make/noload/main.c
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+#include "lib/shared.h"
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from %s.\n", kSharedStr);
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/module/gyptest-default.py b/Source/ThirdParty/gyp/test/module/gyptest-default.py
new file mode 100644
index 000000000..6b1c9b6a8
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/module/gyptest-default.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple build of a "Hello, world!" program with loadable modules. The
+default for all platforms should be to output the loadable modules to the same
+path as the executable.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('module.gyp', chdir='src')
+
+test.build('module.gyp', test.ALL, chdir='src')
+
+expect = """\
+Hello from program.c
+Hello from lib1.c
+Hello from lib2.c
+"""
+test.run_built_executable('program', chdir='src', stdout=expect)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/module/src/lib1.c b/Source/ThirdParty/gyp/test/module/src/lib1.c
new file mode 100644
index 000000000..8de0e94be
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/module/src/lib1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void module_main(void)
+{
+ fprintf(stdout, "Hello from lib1.c\n");
+ fflush(stdout);
+}
diff --git a/Source/ThirdParty/gyp/test/module/src/lib2.c b/Source/ThirdParty/gyp/test/module/src/lib2.c
new file mode 100644
index 000000000..266396dc9
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/module/src/lib2.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+void module_main(void)
+{
+ fprintf(stdout, "Hello from lib2.c\n");
+ fflush(stdout);
+}
diff --git a/Source/ThirdParty/gyp/test/module/src/module.gyp b/Source/ThirdParty/gyp/test/module/src/module.gyp
new file mode 100644
index 000000000..bb43c3023
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/module/src/module.gyp
@@ -0,0 +1,55 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'conditions': [
+ ['OS=="win"', {
+ 'defines': ['PLATFORM_WIN'],
+ }],
+ ['OS=="mac"', {
+ 'defines': ['PLATFORM_MAC'],
+ }],
+ ['OS=="linux"', {
+ 'defines': ['PLATFORM_LINUX'],
+ # Support 64-bit shared libs (also works fine for 32-bit).
+ 'cflags': ['-fPIC'],
+ 'ldflags': ['-ldl'],
+ }],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'dependencies': [
+ 'lib1',
+ 'lib2',
+ ],
+ 'sources': [
+ 'program.c',
+ ],
+ },
+ {
+ 'target_name': 'lib1',
+ 'type': 'loadable_module',
+ 'product_name': 'lib1',
+ 'product_prefix': '',
+ 'xcode_settings': {'OTHER_LDFLAGS': ['-dynamiclib'], 'MACH_O_TYPE': ''},
+ 'sources': [
+ 'lib1.c',
+ ],
+ },
+ {
+ 'target_name': 'lib2',
+ 'product_name': 'lib2',
+ 'product_prefix': '',
+ 'type': 'loadable_module',
+ 'xcode_settings': {'OTHER_LDFLAGS': ['-dynamiclib'], 'MACH_O_TYPE': ''},
+ 'sources': [
+ 'lib2.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/module/src/program.c b/Source/ThirdParty/gyp/test/module/src/program.c
new file mode 100644
index 000000000..b2f332091
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/module/src/program.c
@@ -0,0 +1,111 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(PLATFORM_WIN)
+#include <windows.h>
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+#include <dlfcn.h>
+#include <libgen.h>
+#include <string.h>
+#include <sys/param.h>
+#define MAX_PATH PATH_MAX
+#endif
+
+#if defined(PLATFORM_WIN)
+#define MODULE_SUFFIX ".dll"
+#elif defined(PLATFORM_MAC)
+#define MODULE_SUFFIX ".so"
+#elif defined(PLATFORM_LINUX)
+#define MODULE_SUFFIX ".so"
+#endif
+
+typedef void (*module_symbol)(void);
+char bin_path[MAX_PATH + 1];
+
+
+void CallModule(const char* module) {
+ char module_path[MAX_PATH + 1];
+ const char* module_function = "module_main";
+ module_symbol funcptr;
+#if defined(PLATFORM_WIN)
+ HMODULE dl;
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+
+ if (_splitpath_s(bin_path, drive, _MAX_DRIVE, dir, _MAX_DIR,
+ NULL, 0, NULL, 0)) {
+ fprintf(stderr, "Failed to split executable path.\n");
+ return;
+ }
+ if (_makepath_s(module_path, MAX_PATH, drive, dir, module, MODULE_SUFFIX)) {
+ fprintf(stderr, "Failed to calculate module path.\n");
+ return;
+ }
+
+ dl = LoadLibrary(module_path);
+ if (!dl) {
+ fprintf(stderr, "Failed to open module: %s\n", module_path);
+ return;
+ }
+
+ funcptr = (module_symbol) GetProcAddress(dl, module_function);
+ if (!funcptr) {
+ fprintf(stderr, "Failed to find symbol: %s\n", module_function);
+ return;
+ }
+ funcptr();
+
+ FreeLibrary(dl);
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ void* dl;
+ char* path_copy = strdup(bin_path);
+ char* bin_dir = dirname(path_copy);
+ int path_size = snprintf(module_path, MAX_PATH, "%s/%s%s", bin_dir, module,
+ MODULE_SUFFIX);
+ free(path_copy);
+ if (path_size < 0 || path_size > MAX_PATH) {
+ fprintf(stderr, "Failed to calculate module path.\n");
+ return;
+ }
+ module_path[path_size] = 0;
+
+ dl = dlopen(module_path, RTLD_LAZY);
+ if (!dl) {
+ fprintf(stderr, "Failed to open module: %s\n", module_path);
+ return;
+ }
+
+ funcptr = dlsym(dl, module_function);
+ if (!funcptr) {
+ fprintf(stderr, "Failed to find symbol: %s\n", module_function);
+ return;
+ }
+ funcptr();
+
+ dlclose(dl);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ fprintf(stdout, "Hello from program.c\n");
+ fflush(stdout);
+
+#if defined(PLATFORM_WIN)
+ if (!GetModuleFileName(NULL, bin_path, MAX_PATH)) {
+ fprintf(stderr, "Failed to determine executable path.\n");
+ return;
+ }
+#elif defined(PLATFORM_MAC) || defined(PLATFORM_LINUX)
+ // Using argv[0] should be OK here since we control how the tests run, and
+ // can avoid exec and such issues that make it unreliable.
+ if (!realpath(argv[0], bin_path)) {
+ fprintf(stderr, "Failed to determine executable path (%s).\n", argv[0]);
+ return;
+ }
+#endif
+
+ CallModule("lib1");
+ CallModule("lib2");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/msvs/express/base/base.gyp b/Source/ThirdParty/gyp/test/msvs/express/base/base.gyp
new file mode 100644
index 000000000..b7c9fc6d8
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/msvs/express/base/base.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'a',
+ 'type': 'static_library',
+ 'sources': [
+ 'a.c',
+ ],
+ },
+ {
+ 'target_name': 'b',
+ 'type': 'static_library',
+ 'sources': [
+ 'b.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/msvs/express/express.gyp b/Source/ThirdParty/gyp/test/msvs/express/express.gyp
new file mode 100644
index 000000000..917abe2cc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/msvs/express/express.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'express',
+ 'type': 'executable',
+ 'dependencies': [
+ 'base/base.gyp:a',
+ 'base/base.gyp:b',
+ ],
+ 'sources': [
+ 'main.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/msvs/express/gyptest-express.py b/Source/ThirdParty/gyp/test/msvs/express/gyptest-express.py
new file mode 100644
index 000000000..54c06f664
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/msvs/express/gyptest-express.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that flat solutions get generated for Express versions of
+Visual Studio.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('express.gyp', '-G', 'msvs_version=2005')
+test.must_contain('express.sln', '(base)')
+
+test.run_gyp('express.gyp', '-G', 'msvs_version=2008')
+test.must_contain('express.sln', '(base)')
+
+test.run_gyp('express.gyp', '-G', 'msvs_version=2005e')
+test.must_not_contain('express.sln', '(base)')
+
+test.run_gyp('express.gyp', '-G', 'msvs_version=2008e')
+test.must_not_contain('express.sln', '(base)')
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/msvs/precompiled/gyptest-all.py b/Source/ThirdParty/gyp/test/msvs/precompiled/gyptest-all.py
new file mode 100644
index 000000000..c8d566afe
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/msvs/precompiled/gyptest-all.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that precompiled headers can be specified.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['msvs'])
+
+test.run_gyp('hello.gyp')
+
+test.build('hello.gyp', 'hello')
+
+test.run_built_executable('hello', stdout="Hello, world!\nHello, two!\n")
+
+test.up_to_date('hello.gyp', test.ALL)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/msvs/precompiled/hello.c b/Source/ThirdParty/gyp/test/msvs/precompiled/hello.c
new file mode 100644
index 000000000..d1abbb9e5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/msvs/precompiled/hello.c
@@ -0,0 +1,14 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+// Note the abscence of a stdio.h include. This will be inserted because of the
+// precompiled header.
+
+extern int hello2();
+
+int main(int argc, char *argv[]) {
+ printf("Hello, world!\n");
+ hello2();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/msvs/precompiled/hello.gyp b/Source/ThirdParty/gyp/test/msvs/precompiled/hello.gyp
new file mode 100644
index 000000000..b9533efd8
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/msvs/precompiled/hello.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'hello',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ 'hello2.c',
+ 'precomp.c',
+ ],
+ 'msvs_precompiled_header': 'stdio.h',
+ 'msvs_precompiled_source': 'precomp.c',
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/msvs/precompiled/hello2.c b/Source/ThirdParty/gyp/test/msvs/precompiled/hello2.c
new file mode 100644
index 000000000..d6d53111f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/msvs/precompiled/hello2.c
@@ -0,0 +1,13 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+// Unlike hello.c, this file specifies the headers.
+
+#include <windows.h>
+#include <stdio.h>
+
+int hello2() {
+ printf("Hello, two!\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/msvs/precompiled/precomp.c b/Source/ThirdParty/gyp/test/msvs/precompiled/precomp.c
new file mode 100644
index 000000000..517c61a36
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/msvs/precompiled/precomp.c
@@ -0,0 +1,8 @@
+/* Copyright (c) 2011 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+// The precompiled header does not have to be the first one in the file.
+
+#include <windows.h>
+#include <stdio.h>
diff --git a/Source/ThirdParty/gyp/test/multiple-targets/gyptest-all.py b/Source/ThirdParty/gyp/test/multiple-targets/gyptest-all.py
new file mode 100644
index 000000000..9f157c4f8
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/multiple-targets/gyptest-all.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('multiple.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# TODO(sgk): remove stderr=None when the --generator-output= support
+# gets rid of the scons warning
+test.build('multiple.gyp', test.ALL, chdir='relocate/src', stderr=None)
+
+expect1 = """\
+hello from prog1.c
+hello from common.c
+"""
+
+expect2 = """\
+hello from prog2.c
+hello from common.c
+"""
+
+test.run_built_executable('prog1', stdout=expect1, chdir='relocate/src')
+test.run_built_executable('prog2', stdout=expect2, chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/multiple-targets/gyptest-default.py b/Source/ThirdParty/gyp/test/multiple-targets/gyptest-default.py
new file mode 100644
index 000000000..8d5072d23
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/multiple-targets/gyptest-default.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('multiple.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# TODO(sgk): remove stderr=None when the --generator-output= support
+# gets rid of the scons warning
+test.build('multiple.gyp', chdir='relocate/src', stderr=None)
+
+expect1 = """\
+hello from prog1.c
+hello from common.c
+"""
+
+expect2 = """\
+hello from prog2.c
+hello from common.c
+"""
+
+test.run_built_executable('prog1', stdout=expect1, chdir='relocate/src')
+test.run_built_executable('prog2', stdout=expect2, chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/multiple-targets/src/common.c b/Source/ThirdParty/gyp/test/multiple-targets/src/common.c
new file mode 100644
index 000000000..f1df7c143
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/multiple-targets/src/common.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void common(void)
+{
+ printf("hello from common.c\n");
+ return;
+}
diff --git a/Source/ThirdParty/gyp/test/multiple-targets/src/multiple.gyp b/Source/ThirdParty/gyp/test/multiple-targets/src/multiple.gyp
new file mode 100644
index 000000000..3db4ea30c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/multiple-targets/src/multiple.gyp
@@ -0,0 +1,24 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'prog1',
+ 'type': 'executable',
+ 'sources': [
+ 'prog1.c',
+ 'common.c',
+ ],
+ },
+ {
+ 'target_name': 'prog2',
+ 'type': 'executable',
+ 'sources': [
+ 'prog2.c',
+ 'common.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/multiple-targets/src/prog1.c b/Source/ThirdParty/gyp/test/multiple-targets/src/prog1.c
new file mode 100644
index 000000000..d55f8af1d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/multiple-targets/src/prog1.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void common(void);
+
+int main(int argc, char *argv[])
+{
+ printf("hello from prog1.c\n");
+ common();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/multiple-targets/src/prog2.c b/Source/ThirdParty/gyp/test/multiple-targets/src/prog2.c
new file mode 100644
index 000000000..760590eb6
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/multiple-targets/src/prog2.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void common(void);
+
+int main(int argc, char *argv[])
+{
+ printf("hello from prog2.c\n");
+ common();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/no-output/gyptest-no-output.py b/Source/ThirdParty/gyp/test/no-output/gyptest-no-output.py
new file mode 100644
index 000000000..8431241c5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/no-output/gyptest-no-output.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verified things don't explode when there are targets without outputs.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('nooutput.gyp', chdir='src')
+test.relocate('src', 'relocate/src')
+test.build('nooutput.gyp', chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/no-output/src/nooutput.gyp b/Source/ThirdParty/gyp/test/no-output/src/nooutput.gyp
new file mode 100644
index 000000000..c40124efc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/no-output/src/nooutput.gyp
@@ -0,0 +1,17 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'no_output',
+ 'type': 'none',
+ 'direct_dependent_settings': {
+ 'defines': [
+ 'NADA',
+ ],
+ },
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/product/gyptest-product.py b/Source/ThirdParty/gyp/test/product/gyptest-product.py
new file mode 100644
index 000000000..e9790f30d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/product/gyptest-product.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simplest-possible build of a "Hello, world!" program
+using the default build target.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('product.gyp')
+test.build('product.gyp')
+
+# executables
+test.built_file_must_exist('alt1' + test._exe, test.EXECUTABLE, bare=True)
+test.built_file_must_exist('hello2.stuff', test.EXECUTABLE, bare=True)
+test.built_file_must_exist('yoalt3.stuff', test.EXECUTABLE, bare=True)
+
+# shared libraries
+test.built_file_must_exist(test.dll_ + 'alt4' + test._dll,
+ test.SHARED_LIB, bare=True)
+test.built_file_must_exist(test.dll_ + 'hello5.stuff',
+ test.SHARED_LIB, bare=True)
+test.built_file_must_exist('yoalt6.stuff', test.SHARED_LIB, bare=True)
+
+# static libraries
+test.built_file_must_exist(test.lib_ + 'alt7' + test._lib,
+ test.STATIC_LIB, bare=True)
+test.built_file_must_exist(test.lib_ + 'hello8.stuff',
+ test.STATIC_LIB, bare=True)
+test.built_file_must_exist('yoalt9.stuff', test.STATIC_LIB, bare=True)
+
+# alternate product_dir
+test.built_file_must_exist('bob/yoalt10.stuff', test.EXECUTABLE, bare=True)
+test.built_file_must_exist('bob/yoalt11.stuff', test.EXECUTABLE, bare=True)
+test.built_file_must_exist('bob/yoalt12.stuff', test.EXECUTABLE, bare=True)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/product/hello.c b/Source/ThirdParty/gyp/test/product/hello.c
new file mode 100644
index 000000000..94798f3e7
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/product/hello.c
@@ -0,0 +1,15 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int func1(void) {
+ return 42;
+}
+
+int main(int argc, char *argv[]) {
+ printf("Hello, world!\n");
+ printf("%d\n", func1());
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/product/product.gyp b/Source/ThirdParty/gyp/test/product/product.gyp
new file mode 100644
index 000000000..c25eaaacb
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/product/product.gyp
@@ -0,0 +1,128 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'hello1',
+ 'product_name': 'alt1',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello2',
+ 'product_extension': 'stuff',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello3',
+ 'product_name': 'alt3',
+ 'product_extension': 'stuff',
+ 'product_prefix': 'yo',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+
+ {
+ 'target_name': 'hello4',
+ 'product_name': 'alt4',
+ 'type': 'shared_library',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello5',
+ 'product_extension': 'stuff',
+ 'type': 'shared_library',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello6',
+ 'product_name': 'alt6',
+ 'product_extension': 'stuff',
+ 'product_prefix': 'yo',
+ 'type': 'shared_library',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+
+ {
+ 'target_name': 'hello7',
+ 'product_name': 'alt7',
+ 'type': 'static_library',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello8',
+ 'product_extension': 'stuff',
+ 'type': 'static_library',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello9',
+ 'product_name': 'alt9',
+ 'product_extension': 'stuff',
+ 'product_prefix': 'yo',
+ 'type': 'static_library',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello10',
+ 'product_name': 'alt10',
+ 'product_extension': 'stuff',
+ 'product_prefix': 'yo',
+ 'product_dir': '<(PRODUCT_DIR)/bob',
+ 'type': 'executable',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello11',
+ 'product_name': 'alt11',
+ 'product_extension': 'stuff',
+ 'product_prefix': 'yo',
+ 'product_dir': '<(PRODUCT_DIR)/bob',
+ 'type': 'shared_library',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ {
+ 'target_name': 'hello12',
+ 'product_name': 'alt12',
+ 'product_extension': 'stuff',
+ 'product_prefix': 'yo',
+ 'product_dir': '<(PRODUCT_DIR)/bob',
+ 'type': 'static_library',
+ 'sources': [
+ 'hello.c',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'target_defaults': {
+ 'cflags': ['-fPIC'],
+ },
+ }],
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/rules-rebuild/gyptest-all.py b/Source/ThirdParty/gyp/test/rules-rebuild/gyptest-all.py
new file mode 100644
index 000000000..ec1c74661
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules-rebuild/gyptest-all.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a rule that generates multiple outputs rebuilds
+correctly when the inputs change.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('same_target.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+
+test.build('same_target.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in!
+Hello from prog2.in!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'prog1.in'])
+contents = contents.replace('!', ' AGAIN!')
+test.write(['relocate', 'src', 'prog1.in'], contents)
+
+test.build('same_target.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in AGAIN!
+Hello from prog2.in!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'prog2.in'])
+contents = contents.replace('!', ' AGAIN!')
+test.write(['relocate', 'src', 'prog2.in'], contents)
+
+test.build('same_target.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in AGAIN!
+Hello from prog2.in AGAIN!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/rules-rebuild/gyptest-default.py b/Source/ThirdParty/gyp/test/rules-rebuild/gyptest-default.py
new file mode 100644
index 000000000..74440d157
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules-rebuild/gyptest-default.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a rule that generates multiple outputs rebuilds
+correctly when the inputs change.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('same_target.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+
+test.build('same_target.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in!
+Hello from prog2.in!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'prog1.in'])
+contents = contents.replace('!', ' AGAIN!')
+test.write(['relocate', 'src', 'prog1.in'], contents)
+
+test.build('same_target.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in AGAIN!
+Hello from prog2.in!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.sleep()
+contents = test.read(['relocate', 'src', 'prog2.in'])
+contents = contents.replace('!', ' AGAIN!')
+test.write(['relocate', 'src', 'prog2.in'], contents)
+
+test.build('same_target.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from main.c
+Hello from prog1.in AGAIN!
+Hello from prog2.in AGAIN!
+"""
+
+test.run_built_executable('program', chdir='relocate/src', stdout=expect)
+
+test.up_to_date('same_target.gyp', 'program', chdir='relocate/src')
+
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/rules-rebuild/src/main.c b/Source/ThirdParty/gyp/test/rules-rebuild/src/main.c
new file mode 100644
index 000000000..bdc5ec875
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules-rebuild/src/main.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern void prog1(void);
+extern void prog2(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from main.c\n");
+ prog1();
+ prog2();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/rules-rebuild/src/make-sources.py b/Source/ThirdParty/gyp/test/rules-rebuild/src/make-sources.py
new file mode 100644
index 000000000..6fce558b2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules-rebuild/src/make-sources.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+import sys
+
+assert len(sys.argv) == 4, sys.argv
+
+(in_file, c_file, h_file) = sys.argv[1:]
+
+def write_file(filename, contents):
+ open(filename, 'wb').write(contents)
+
+write_file(c_file, open(in_file, 'rb').read())
+
+write_file(h_file, '#define NAME "%s"\n' % in_file)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/rules-rebuild/src/prog1.in b/Source/ThirdParty/gyp/test/rules-rebuild/src/prog1.in
new file mode 100644
index 000000000..191b00ef1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules-rebuild/src/prog1.in
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "prog1.h"
+
+void prog1(void)
+{
+ printf("Hello from %s!\n", NAME);
+}
diff --git a/Source/ThirdParty/gyp/test/rules-rebuild/src/prog2.in b/Source/ThirdParty/gyp/test/rules-rebuild/src/prog2.in
new file mode 100644
index 000000000..7bfac5104
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules-rebuild/src/prog2.in
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include "prog2.h"
+
+void prog2(void)
+{
+ printf("Hello from %s!\n", NAME);
+}
diff --git a/Source/ThirdParty/gyp/test/rules-rebuild/src/same_target.gyp b/Source/ThirdParty/gyp/test/rules-rebuild/src/same_target.gyp
new file mode 100644
index 000000000..22ba56056
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules-rebuild/src/same_target.gyp
@@ -0,0 +1,31 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'main.c',
+ 'prog1.in',
+ 'prog2.in',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'make_sources',
+ 'extension': 'in',
+ 'inputs': [
+ 'make-sources.py',
+ ],
+ 'outputs': [
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c',
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).h',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_NAME)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/rules/gyptest-all.py b/Source/ThirdParty/gyp/test/rules/gyptest-all.py
new file mode 100644
index 000000000..8a69d6040
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/gyptest-all.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple rules when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('actions.gyp', test.ALL, chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from function1.in
+Hello from function2.in
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir1'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+expect = """\
+Hello from program.c
+Hello from function3.in
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir3'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('program2', chdir=chdir, stdout=expect)
+
+test.must_match('relocate/src/subdir2/file1.out', "Hello from file1.in\n")
+test.must_match('relocate/src/subdir2/file2.out', "Hello from file2.in\n")
+
+test.must_match('relocate/src/subdir2/file1.out2', "Hello from file1.in\n")
+test.must_match('relocate/src/subdir2/file2.out2', "Hello from file2.in\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/rules/gyptest-default.py b/Source/ThirdParty/gyp/test/rules/gyptest-default.py
new file mode 100644
index 000000000..ef5fc61fd
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/gyptest-default.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies simple rules when using an explicit build target of 'all'.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('actions.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('actions.gyp', chdir='relocate/src')
+
+expect = """\
+Hello from program.c
+Hello from function1.in
+Hello from function2.in
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir1'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('program', chdir=chdir, stdout=expect)
+
+expect = """\
+Hello from program.c
+Hello from function3.in
+"""
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir3'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('program2', chdir=chdir, stdout=expect)
+
+test.must_match('relocate/src/subdir2/file1.out', "Hello from file1.in\n")
+test.must_match('relocate/src/subdir2/file2.out', "Hello from file2.in\n")
+
+test.must_match('relocate/src/subdir2/file1.out2', "Hello from file1.in\n")
+test.must_match('relocate/src/subdir2/file2.out2', "Hello from file2.in\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/rules/src/actions.gyp b/Source/ThirdParty/gyp/test/rules/src/actions.gyp
new file mode 100644
index 000000000..d5c32cf6c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/actions.gyp
@@ -0,0 +1,19 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'pull_in_all_actions',
+ 'type': 'none',
+ 'dependencies': [
+ 'subdir1/executable.gyp:*',
+ 'subdir2/never_used.gyp:*',
+ 'subdir2/no_inputs.gyp:*',
+ 'subdir2/none.gyp:*',
+ 'subdir3/executable2.gyp:*',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/copy-file.py b/Source/ThirdParty/gyp/test/rules/src/copy-file.py
new file mode 100644
index 000000000..5a5feae1f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/copy-file.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+import sys
+
+contents = open(sys.argv[1], 'r').read()
+open(sys.argv[2], 'wb').write(contents)
+
+sys.exit(0)
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir1/executable.gyp b/Source/ThirdParty/gyp/test/rules/src/subdir1/executable.gyp
new file mode 100644
index 000000000..302857789
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir1/executable.gyp
@@ -0,0 +1,37 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'program.c',
+ 'function1.in',
+ 'function2.in',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'copy_file',
+ 'extension': 'in',
+ 'inputs': [
+ '../copy-file.py',
+ ],
+ 'outputs': [
+ # TODO: fix SCons and Make to support generated files not
+ # in a variable-named path like <(INTERMEDIATE_DIR)
+ #'<(RULE_INPUT_ROOT).c',
+ '<(INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).c',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir1/function1.in b/Source/ThirdParty/gyp/test/rules/src/subdir1/function1.in
new file mode 100644
index 000000000..60ff28949
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir1/function1.in
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void function1(void)
+{
+ printf("Hello from function1.in\n");
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir1/function2.in b/Source/ThirdParty/gyp/test/rules/src/subdir1/function2.in
new file mode 100644
index 000000000..0fcfc03fd
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir1/function2.in
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void function2(void)
+{
+ printf("Hello from function2.in\n");
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir1/program.c b/Source/ThirdParty/gyp/test/rules/src/subdir1/program.c
new file mode 100644
index 000000000..258d7f99e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir1/program.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+extern void function1(void);
+extern void function2(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from program.c\n");
+ function1();
+ function2();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir2/file1.in b/Source/ThirdParty/gyp/test/rules/src/subdir2/file1.in
new file mode 100644
index 000000000..86ac3ad38
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir2/file1.in
@@ -0,0 +1 @@
+Hello from file1.in
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir2/file2.in b/Source/ThirdParty/gyp/test/rules/src/subdir2/file2.in
new file mode 100644
index 000000000..bf83d8ece
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir2/file2.in
@@ -0,0 +1 @@
+Hello from file2.in
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir2/never_used.gyp b/Source/ThirdParty/gyp/test/rules/src/subdir2/never_used.gyp
new file mode 100644
index 000000000..17f6f5537
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir2/never_used.gyp
@@ -0,0 +1,31 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Test that the case where there is a rule that doesn't apply to anything.
+{
+ 'targets': [
+ {
+ 'target_name': 'files_no_input2',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'file1.in',
+ 'file2.in',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'copy_file3',
+ 'extension': 'in2',
+ 'outputs': [
+ '<(RULE_INPUT_ROOT).out3',
+ ],
+ 'action': [
+ 'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir2/no_inputs.gyp b/Source/ThirdParty/gyp/test/rules/src/subdir2/no_inputs.gyp
new file mode 100644
index 000000000..e61a1a3ff
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir2/no_inputs.gyp
@@ -0,0 +1,32 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Test that the case where there are no inputs (other than the
+# file the rule applies to).
+{
+ 'targets': [
+ {
+ 'target_name': 'files_no_input',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'file1.in',
+ 'file2.in',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'copy_file2',
+ 'extension': 'in',
+ 'outputs': [
+ '<(RULE_INPUT_ROOT).out2',
+ ],
+ 'action': [
+ 'python', '../copy-file.py', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir2/none.gyp b/Source/ThirdParty/gyp/test/rules/src/subdir2/none.gyp
new file mode 100644
index 000000000..38bcdabdf
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir2/none.gyp
@@ -0,0 +1,33 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'files',
+ 'type': 'none',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'file1.in',
+ 'file2.in',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'copy_file',
+ 'extension': 'in',
+ 'inputs': [
+ '../copy-file.py',
+ ],
+ 'outputs': [
+ '<(RULE_INPUT_ROOT).out',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir3/executable2.gyp b/Source/ThirdParty/gyp/test/rules/src/subdir3/executable2.gyp
new file mode 100644
index 000000000..a2a528fc7
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir3/executable2.gyp
@@ -0,0 +1,37 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This one tests that rules are properly written if extensions are different
+# between the target's sources (program.c) and the generated files
+# (function3.cc)
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program2',
+ 'type': 'executable',
+ 'msvs_cygwin_shell': 0,
+ 'sources': [
+ 'program.c',
+ 'function3.in',
+ ],
+ 'rules': [
+ {
+ 'rule_name': 'copy_file',
+ 'extension': 'in',
+ 'inputs': [
+ '../copy-file.py',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/<(RULE_INPUT_ROOT).cc',
+ ],
+ 'action': [
+ 'python', '<(_inputs)', '<(RULE_INPUT_PATH)', '<@(_outputs)',
+ ],
+ 'process_outputs_as_sources': 1,
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir3/function3.in b/Source/ThirdParty/gyp/test/rules/src/subdir3/function3.in
new file mode 100644
index 000000000..99f46ab05
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir3/function3.in
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+extern "C" void function3(void)
+{
+ printf("Hello from function3.in\n");
+}
diff --git a/Source/ThirdParty/gyp/test/rules/src/subdir3/program.c b/Source/ThirdParty/gyp/test/rules/src/subdir3/program.c
new file mode 100644
index 000000000..94f6c5091
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/rules/src/subdir3/program.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+extern void function3(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from program.c\n");
+ function3();
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/same-gyp-name/gyptest-all.py b/Source/ThirdParty/gyp/test/same-gyp-name/gyptest-all.py
new file mode 100644
index 000000000..76456885e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-gyp-name/gyptest-all.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build a .gyp that depends on 2 gyp files with the same name.
+"""
+
+import TestGyp
+
+# This causes a problem on XCode (duplicate ID).
+# See http://code.google.com/p/gyp/issues/detail?id=114
+test = TestGyp.TestGyp(formats=['msvs', 'scons', 'make'])
+
+test.run_gyp('all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+expect1 = """\
+Hello from main1.cc
+"""
+
+expect2 = """\
+Hello from main2.cc
+"""
+
+test.run_built_executable('program1', chdir='relocate/src', stdout=expect1)
+test.run_built_executable('program2', chdir='relocate/src', stdout=expect2)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/same-gyp-name/gyptest-default.py b/Source/ThirdParty/gyp/test/same-gyp-name/gyptest-default.py
new file mode 100644
index 000000000..c1031f86b
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-gyp-name/gyptest-default.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build a .gyp that depends on 2 gyp files with the same name.
+"""
+
+import TestGyp
+
+# This causes a problem on XCode (duplicate ID).
+# See http://code.google.com/p/gyp/issues/detail?id=114
+test = TestGyp.TestGyp(formats=['msvs', 'scons', 'make'])
+
+test.run_gyp('all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', chdir='relocate/src')
+
+expect1 = """\
+Hello from main1.cc
+"""
+
+expect2 = """\
+Hello from main2.cc
+"""
+
+test.run_built_executable('program1', chdir='relocate/src', stdout=expect1)
+test.run_built_executable('program2', chdir='relocate/src', stdout=expect2)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/same-gyp-name/src/all.gyp b/Source/ThirdParty/gyp/test/same-gyp-name/src/all.gyp
new file mode 100644
index 000000000..229f02ea8
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-gyp-name/src/all.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'all_exes',
+ 'type': 'none',
+ 'dependencies': [
+ 'subdir1/executable.gyp:*',
+ 'subdir2/executable.gyp:*',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir1/executable.gyp b/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir1/executable.gyp
new file mode 100644
index 000000000..82483b4c6
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir1/executable.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program1',
+ 'type': 'executable',
+ 'sources': [
+ 'main1.cc',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir1/main1.cc b/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir1/main1.cc
new file mode 100644
index 000000000..364555832
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir1/main1.cc
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main() {
+ printf("Hello from main1.cc\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir2/executable.gyp b/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir2/executable.gyp
new file mode 100644
index 000000000..e3537013e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir2/executable.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program2',
+ 'type': 'executable',
+ 'sources': [
+ 'main2.cc',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir2/main2.cc b/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir2/main2.cc
new file mode 100644
index 000000000..0c724dee3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-gyp-name/src/subdir2/main2.cc
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main() {
+ printf("Hello from main2.cc\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/same-name/gyptest-all.py b/Source/ThirdParty/gyp/test/same-name/gyptest-all.py
new file mode 100644
index 000000000..4c215027c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-name/gyptest-all.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build a .gyp with two targets that share a common .c source file.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', test.ALL, chdir='relocate/src')
+
+expect1 = """\
+Hello from prog1.c
+Hello prog1 from func.c
+"""
+
+expect2 = """\
+Hello from prog2.c
+Hello prog2 from func.c
+"""
+
+test.run_built_executable('prog1', chdir='relocate/src', stdout=expect1)
+test.run_built_executable('prog2', chdir='relocate/src', stdout=expect2)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/same-name/gyptest-default.py b/Source/ThirdParty/gyp/test/same-name/gyptest-default.py
new file mode 100644
index 000000000..98757c269
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-name/gyptest-default.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Build a .gyp with two targets that share a common .c source file.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('all.gyp', chdir='relocate/src')
+
+expect1 = """\
+Hello from prog1.c
+Hello prog1 from func.c
+"""
+
+expect2 = """\
+Hello from prog2.c
+Hello prog2 from func.c
+"""
+
+test.run_built_executable('prog1', chdir='relocate/src', stdout=expect1)
+test.run_built_executable('prog2', chdir='relocate/src', stdout=expect2)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/same-name/src/all.gyp b/Source/ThirdParty/gyp/test/same-name/src/all.gyp
new file mode 100644
index 000000000..44e104982
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-name/src/all.gyp
@@ -0,0 +1,38 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'prog1',
+ 'type': 'executable',
+ 'defines': [
+ 'PROG="prog1"',
+ ],
+ 'sources': [
+ 'prog1.c',
+ 'func.c',
+ # Uncomment to test same-named files in different directories,
+ # which Visual Studio doesn't support.
+ #'subdir1/func.c',
+ #'subdir2/func.c',
+ ],
+ },
+ {
+ 'target_name': 'prog2',
+ 'type': 'executable',
+ 'defines': [
+ 'PROG="prog2"',
+ ],
+ 'sources': [
+ 'prog2.c',
+ 'func.c',
+ # Uncomment to test same-named files in different directories,
+ # which Visual Studio doesn't support.
+ #'subdir1/func.c',
+ #'subdir2/func.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/same-name/src/func.c b/Source/ThirdParty/gyp/test/same-name/src/func.c
new file mode 100644
index 000000000..e069c692a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-name/src/func.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void func(void)
+{
+ printf("Hello %s from func.c\n", PROG);
+}
diff --git a/Source/ThirdParty/gyp/test/same-name/src/prog1.c b/Source/ThirdParty/gyp/test/same-name/src/prog1.c
new file mode 100644
index 000000000..c8940fedc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-name/src/prog1.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void func(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog1.c\n");
+ func();
+ /*
+ * Uncomment to test same-named files in different directories,
+ * which Visual Studio doesn't support.
+ subdir1_func();
+ subdir2_func();
+ */
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/same-name/src/prog2.c b/Source/ThirdParty/gyp/test/same-name/src/prog2.c
new file mode 100644
index 000000000..e6605c2bd
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-name/src/prog2.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+
+extern void func(void);
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog2.c\n");
+ func();
+ /*
+ * Uncomment to test same-named files in different directories,
+ * which Visual Studio doesn't support.
+ subdir1_func();
+ subdir2_func();
+ */
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/same-name/src/subdir1/func.c b/Source/ThirdParty/gyp/test/same-name/src/subdir1/func.c
new file mode 100644
index 000000000..b73450d10
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-name/src/subdir1/func.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void subdir1_func(void)
+{
+ printf("Hello %s from subdir1/func.c\n", PROG);
+}
diff --git a/Source/ThirdParty/gyp/test/same-name/src/subdir2/func.c b/Source/ThirdParty/gyp/test/same-name/src/subdir2/func.c
new file mode 100644
index 000000000..0248b5720
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-name/src/subdir2/func.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void subdir2_func(void)
+{
+ printf("Hello %s from subdir2/func.c\n", PROG);
+}
diff --git a/Source/ThirdParty/gyp/test/same-target-name/gyptest-same-target-name.py b/Source/ThirdParty/gyp/test/same-target-name/gyptest-same-target-name.py
new file mode 100644
index 000000000..bfe5540f3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-target-name/gyptest-same-target-name.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Check that duplicate targets in a directory gives an error.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+# Require that gyp files with duplicate targets spit out an error.
+test.run_gyp('all.gyp', chdir='src', status=1, stderr=None)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/same-target-name/src/all.gyp b/Source/ThirdParty/gyp/test/same-target-name/src/all.gyp
new file mode 100644
index 000000000..ac16976da
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-target-name/src/all.gyp
@@ -0,0 +1,16 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'all_exes',
+ 'type': 'none',
+ 'dependencies': [
+ 'executable1.gyp:*',
+ 'executable2.gyp:*',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/same-target-name/src/executable1.gyp b/Source/ThirdParty/gyp/test/same-target-name/src/executable1.gyp
new file mode 100644
index 000000000..3c492c1b3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-target-name/src/executable1.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'sources': [
+ 'main1.cc',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/same-target-name/src/executable2.gyp b/Source/ThirdParty/gyp/test/same-target-name/src/executable2.gyp
new file mode 100644
index 000000000..41e84a61c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/same-target-name/src/executable2.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'program',
+ 'type': 'executable',
+ 'sources': [
+ 'main2.cc',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/scons_tools/gyptest-tools.py b/Source/ThirdParty/gyp/test/scons_tools/gyptest-tools.py
new file mode 100755
index 000000000..e97f5e631
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/scons_tools/gyptest-tools.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that a scons build picks up tools modules specified
+via 'scons_tools' in the 'scons_settings' dictionary.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('tools.gyp')
+
+test.build('tools.gyp', test.ALL)
+
+if test.format == 'scons':
+ expect = "Hello, world!\n"
+else:
+ expect = ""
+test.run_built_executable('tools', stdout=expect)
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/scons_tools/site_scons/site_tools/this_tool.py b/Source/ThirdParty/gyp/test/scons_tools/site_scons/site_tools/this_tool.py
new file mode 100644
index 000000000..10c89476d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/scons_tools/site_scons/site_tools/this_tool.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# SCons "tool" module that simply sets a -D value.
+def generate(env):
+ env['CPPDEFINES'] = ['THIS_TOOL']
+
+def exists(env):
+ pass
diff --git a/Source/ThirdParty/gyp/test/scons_tools/tools.c b/Source/ThirdParty/gyp/test/scons_tools/tools.c
new file mode 100644
index 000000000..78dc0e31e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/scons_tools/tools.c
@@ -0,0 +1,13 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+#ifdef THIS_TOOL
+ printf("Hello, world!\n");
+#endif
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/scons_tools/tools.gyp b/Source/ThirdParty/gyp/test/scons_tools/tools.gyp
new file mode 100644
index 000000000..736ba3f22
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/scons_tools/tools.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'tools',
+ 'type': 'executable',
+ 'sources': [
+ 'tools.c',
+ ],
+ },
+ ],
+ 'scons_settings': {
+ 'tools': ['default', 'this_tool'],
+ },
+}
diff --git a/Source/ThirdParty/gyp/test/sibling/gyptest-all.py b/Source/ThirdParty/gyp/test/sibling/gyptest-all.py
new file mode 100644
index 000000000..c04c2d486
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/sibling/gyptest-all.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('build/all.gyp', chdir='src')
+
+test.build('build/all.gyp', test.ALL, chdir='src')
+
+chdir = 'src/build'
+
+# The top-level Makefile is in the directory where gyp was run.
+# TODO(mmoss) Should the Makefile go in the directory of the passed in .gyp
+# file? What about when passing in multiple .gyp files? Would sub-project
+# Makefiles (see http://codereview.chromium.org/340008 comments) solve this?
+if test.format == 'make':
+ chdir = 'src'
+
+if test.format == 'xcode':
+ chdir = 'src/prog1'
+test.run_built_executable('prog1',
+ chdir=chdir,
+ stdout="Hello from prog1.c\n")
+
+if test.format == 'xcode':
+ chdir = 'src/prog2'
+test.run_built_executable('prog2',
+ chdir=chdir,
+ stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/sibling/gyptest-relocate.py b/Source/ThirdParty/gyp/test/sibling/gyptest-relocate.py
new file mode 100644
index 000000000..176545fa6
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/sibling/gyptest-relocate.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('build/all.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('build/all.gyp', test.ALL, chdir='relocate/src')
+
+chdir = 'relocate/src/build'
+
+# The top-level Makefile is in the directory where gyp was run.
+# TODO(mmoss) Should the Makefile go in the directory of the passed in .gyp
+# file? What about when passing in multiple .gyp files? Would sub-project
+# Makefiles (see http://codereview.chromium.org/340008 comments) solve this?
+if test.format == 'make':
+ chdir = 'relocate/src'
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/prog1'
+test.run_built_executable('prog1',
+ chdir=chdir,
+ stdout="Hello from prog1.c\n")
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/prog2'
+test.run_built_executable('prog2',
+ chdir=chdir,
+ stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/sibling/src/prog1/prog1.c b/Source/ThirdParty/gyp/test/sibling/src/prog1/prog1.c
new file mode 100644
index 000000000..161ae8a38
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/sibling/src/prog1/prog1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog1.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/sibling/src/prog1/prog1.gyp b/Source/ThirdParty/gyp/test/sibling/src/prog1/prog1.gyp
new file mode 100644
index 000000000..fbe38b97a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/sibling/src/prog1/prog1.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'prog1',
+ 'type': 'executable',
+ 'sources': [
+ 'prog1.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/sibling/src/prog2/prog2.c b/Source/ThirdParty/gyp/test/sibling/src/prog2/prog2.c
new file mode 100644
index 000000000..7635ae8c1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/sibling/src/prog2/prog2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog2.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/sibling/src/prog2/prog2.gyp b/Source/ThirdParty/gyp/test/sibling/src/prog2/prog2.gyp
new file mode 100644
index 000000000..593454836
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/sibling/src/prog2/prog2.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'prog2',
+ 'type': 'executable',
+ 'sources': [
+ 'prog2.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/small/gyptest-small.py b/Source/ThirdParty/gyp/test/small/gyptest-small.py
new file mode 100755
index 000000000..38299b3a7
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/small/gyptest-small.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Runs small tests.
+"""
+
+import imp
+import os
+import sys
+import unittest
+
+import TestGyp
+
+
+test = TestGyp.TestGyp()
+
+# Add pylib/gyp to the import path (so tests can import their dependencies).
+sys.path.append(os.path.join(test._cwd, 'pylib', 'gyp'))
+
+# Add new test suites here.
+files_to_test = [
+ 'pylib/gyp/MSVSSettings_test.py',
+ 'pylib/gyp/easy_xml_test.py',
+]
+
+# Collect all the suites from the above files.
+suites = []
+for filename in files_to_test:
+ # Carve the module name out of the path.
+ name = os.path.splitext(os.path.split(filename)[1])[0]
+ # Find the complete module path.
+ full_filename = os.path.join(test._cwd, filename)
+ # Load the module.
+ module = imp.load_source(name, full_filename)
+ # Add it to the list of test suites.
+ suites.append(unittest.defaultTestLoader.loadTestsFromModule(module))
+# Create combined suite.
+all_tests = unittest.TestSuite(suites)
+
+# Run all the tests.
+result = unittest.TextTestRunner(verbosity=2).run(all_tests)
+if result.failures or result.errors:
+ test.fail_test()
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/subdirectory/gyptest-SYMROOT-all.py b/Source/ThirdParty/gyp/test/subdirectory/gyptest-SYMROOT-all.py
new file mode 100644
index 000000000..b7509041a
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/gyptest-SYMROOT-all.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target and a subsidiary dependent target from a
+.gyp file in a subdirectory, without specifying an explicit output build
+directory, and using the generated solution or project file at the top
+of the tree as the entry point.
+
+The configuration sets the Xcode SYMROOT variable and uses --depth=
+to make Xcode behave like the other build tools--that is, put all
+built targets in a single output build directory at the top of the tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', '-Dset_symroot=1', '--depth=.', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Suppress the test infrastructure's setting SYMROOT on the command line.
+test.build('prog1.gyp', test.ALL, SYMROOT=None, chdir='relocate/src')
+
+test.run_built_executable('prog1',
+ stdout="Hello from prog1.c\n",
+ chdir='relocate/src')
+test.run_built_executable('prog2',
+ stdout="Hello from prog2.c\n",
+ chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/subdirectory/gyptest-SYMROOT-default.py b/Source/ThirdParty/gyp/test/subdirectory/gyptest-SYMROOT-default.py
new file mode 100644
index 000000000..c64ae7da3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/gyptest-SYMROOT-default.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target and a subsidiary dependent target from a
+.gyp file in a subdirectory, without specifying an explicit output build
+directory, and using the generated solution or project file at the top
+of the tree as the entry point.
+
+The configuration sets the Xcode SYMROOT variable and uses --depth=
+to make Xcode behave like the other build tools--that is, put all
+built targets in a single output build directory at the top of the tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', '-Dset_symroot=1', '--depth=.', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+# Suppress the test infrastructure's setting SYMROOT on the command line.
+test.build('prog1.gyp', SYMROOT=None, chdir='relocate/src')
+
+test.run_built_executable('prog1',
+ stdout="Hello from prog1.c\n",
+ chdir='relocate/src')
+
+test.run_built_executable('prog2',
+ stdout="Hello from prog2.c\n",
+ chdir='relocate/src')
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir-all.py b/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir-all.py
new file mode 100644
index 000000000..fbaef322c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir-all.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a subsidiary dependent target from a .gyp file in a
+subdirectory, without specifying an explicit output build directory,
+and using the subdirectory's solution or project file as the entry point.
+"""
+
+import TestGyp
+import errno
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+chdir = 'relocate/src/subdir'
+target = test.ALL
+
+test.build('prog2.gyp', target, chdir=chdir)
+
+test.built_file_must_not_exist('prog1', type=test.EXECUTABLE, chdir=chdir)
+
+test.run_built_executable('prog2',
+ chdir=chdir,
+ stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir-default.py b/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir-default.py
new file mode 100644
index 000000000..6372ea2a3
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir-default.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a subsidiary dependent target from a .gyp file in a
+subdirectory, without specifying an explicit output build directory,
+and using the subdirectory's solution or project file as the entry point.
+"""
+
+import TestGyp
+import errno
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+chdir = 'relocate/src/subdir'
+
+test.build('prog2.gyp', chdir=chdir)
+
+test.built_file_must_not_exist('prog1', type=test.EXECUTABLE, chdir=chdir)
+
+test.run_built_executable('prog2',
+ chdir=chdir,
+ stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir2-deep.py b/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir2-deep.py
new file mode 100644
index 000000000..48548982f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/gyptest-subdir2-deep.py
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a project rooted several layers under src_dir works.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog3.gyp', chdir='src/subdir/subdir2')
+
+test.relocate('src', 'relocate/src')
+
+test.build('prog3.gyp', test.ALL, chdir='relocate/src/subdir/subdir2')
+
+test.run_built_executable('prog3',
+ chdir='relocate/src/subdir/subdir2',
+ stdout="Hello from prog3.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/subdirectory/gyptest-top-all.py b/Source/ThirdParty/gyp/test/subdirectory/gyptest-top-all.py
new file mode 100644
index 000000000..a29a41b4d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/gyptest-top-all.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target and a subsidiary dependent target from a
+.gyp file in a subdirectory, without specifying an explicit output build
+directory, and using the generated solution or project file at the top
+of the tree as the entry point.
+
+There is a difference here in the default behavior of the underlying
+build tools. Specifically, when building the entire "solution", Xcode
+puts the output of each project relative to the .xcodeproj directory,
+while Visual Studio (and our implementations of SCons and Make) put it
+in a build directory relative to the "solution"--that is, the entry-point
+from which you built the entire tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('prog1.gyp', test.ALL, chdir='relocate/src')
+
+test.run_built_executable('prog1',
+ stdout="Hello from prog1.c\n",
+ chdir='relocate/src')
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('prog2',
+ chdir=chdir,
+ stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/subdirectory/gyptest-top-default.py b/Source/ThirdParty/gyp/test/subdirectory/gyptest-top-default.py
new file mode 100644
index 000000000..ac5f60dbc
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/gyptest-top-default.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a target and a subsidiary dependent target from a
+.gyp file in a subdirectory, without specifying an explicit output build
+directory, and using the generated solution or project file at the top
+of the tree as the entry point.
+
+There is a difference here in the default behavior of the underlying
+build tools. Specifically, when building the entire "solution", Xcode
+puts the output of each project relative to the .xcodeproj directory,
+while Visual Studio (and our implementations of SCons and Make) put it
+in a build directory relative to the "solution"--that is, the entry-point
+from which you built the entire tree.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp()
+
+test.run_gyp('prog1.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('prog1.gyp', chdir='relocate/src')
+
+test.run_built_executable('prog1',
+ stdout="Hello from prog1.c\n",
+ chdir='relocate/src')
+
+if test.format == 'xcode':
+ chdir = 'relocate/src/subdir'
+else:
+ chdir = 'relocate/src'
+test.run_built_executable('prog2',
+ chdir=chdir,
+ stdout="Hello from prog2.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/subdirectory/src/prog1.c b/Source/ThirdParty/gyp/test/subdirectory/src/prog1.c
new file mode 100644
index 000000000..161ae8a38
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/src/prog1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog1.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/subdirectory/src/prog1.gyp b/Source/ThirdParty/gyp/test/subdirectory/src/prog1.gyp
new file mode 100644
index 000000000..2aa66ce7d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/src/prog1.gyp
@@ -0,0 +1,21 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ 'symroot.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog1',
+ 'type': 'executable',
+ 'dependencies': [
+ 'subdir/prog2.gyp:prog2',
+ ],
+ 'sources': [
+ 'prog1.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/subdirectory/src/subdir/prog2.c b/Source/ThirdParty/gyp/test/subdirectory/src/subdir/prog2.c
new file mode 100644
index 000000000..7635ae8c1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/src/subdir/prog2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog2.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/subdirectory/src/subdir/prog2.gyp b/Source/ThirdParty/gyp/test/subdirectory/src/subdir/prog2.gyp
new file mode 100644
index 000000000..c6cd35f7f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/src/subdir/prog2.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../symroot.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog2',
+ 'type': 'executable',
+ 'sources': [
+ 'prog2.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/subdirectory/src/subdir/subdir2/prog3.c b/Source/ThirdParty/gyp/test/subdirectory/src/subdir/subdir2/prog3.c
new file mode 100644
index 000000000..7cfb0fa94
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/src/subdir/subdir2/prog3.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog3.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp b/Source/ThirdParty/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp
new file mode 100644
index 000000000..b49fb5911
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/src/subdir/subdir2/prog3.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../../symroot.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'prog3',
+ 'type': 'executable',
+ 'sources': [
+ 'prog3.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/subdirectory/src/symroot.gypi b/Source/ThirdParty/gyp/test/subdirectory/src/symroot.gypi
new file mode 100644
index 000000000..519916427
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/subdirectory/src/symroot.gypi
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'set_symroot%': 0,
+ },
+ 'conditions': [
+ ['set_symroot == 1', {
+ 'xcode_settings': {
+ 'SYMROOT': '<(DEPTH)/build',
+ },
+ }],
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/toolsets/gyptest-toolsets.py b/Source/ThirdParty/gyp/test/toolsets/gyptest-toolsets.py
new file mode 100644
index 000000000..19737f83d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toolsets/gyptest-toolsets.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that toolsets are correctly applied
+"""
+
+import TestGyp
+
+# Multiple toolsets are currently only supported by the make generator.
+test = TestGyp.TestGyp(formats=['make'])
+
+test.run_gyp('toolsets.gyp')
+
+test.build('toolsets.gyp', test.ALL)
+
+test.run_built_executable('host-main', stdout="Host\n")
+test.run_built_executable('target-main', stdout="Target\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/toolsets/main.cc b/Source/ThirdParty/gyp/test/toolsets/main.cc
new file mode 100644
index 000000000..0f353ae54
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toolsets/main.cc
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+#include <stdio.h>
+
+const char *GetToolset();
+
+int main(int argc, char *argv[]) {
+ printf("%s\n", GetToolset());
+}
diff --git a/Source/ThirdParty/gyp/test/toolsets/toolsets.cc b/Source/ThirdParty/gyp/test/toolsets/toolsets.cc
new file mode 100644
index 000000000..a45fa029c
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toolsets/toolsets.cc
@@ -0,0 +1,11 @@
+/* Copyright (c) 2009 Google Inc. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+const char *GetToolset() {
+#ifdef TARGET
+ return "Target";
+#else
+ return "Host";
+#endif
+}
diff --git a/Source/ThirdParty/gyp/test/toolsets/toolsets.gyp b/Source/ThirdParty/gyp/test/toolsets/toolsets.gyp
new file mode 100644
index 000000000..e41b928de
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toolsets/toolsets.gyp
@@ -0,0 +1,38 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'target_conditions': [
+ ['_toolset=="target"', {'defines': ['TARGET']}]
+ ]
+ },
+ 'targets': [
+ {
+ 'target_name': 'toolsets',
+ 'type': 'static_library',
+ 'toolsets': ['target', 'host'],
+ 'sources': [
+ 'toolsets.cc',
+ ],
+ },
+ {
+ 'target_name': 'host-main',
+ 'type': 'executable',
+ 'toolsets': ['host'],
+ 'dependencies': ['toolsets'],
+ 'sources': [
+ 'main.cc',
+ ],
+ },
+ {
+ 'target_name': 'target-main',
+ 'type': 'executable',
+ 'dependencies': ['toolsets'],
+ 'sources': [
+ 'main.cc',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/toplevel-dir/gyptest-toplevel-dir.py b/Source/ThirdParty/gyp/test/toplevel-dir/gyptest-toplevel-dir.py
new file mode 100644
index 000000000..61986cdaa
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toplevel-dir/gyptest-toplevel-dir.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies building a subsidiary dependent target from a .gyp file in a
+subdirectory, without specifying an explicit output build directory,
+and using the subdirectory's solution or project file as the entry point.
+"""
+
+import TestGyp
+import errno
+
+test = TestGyp.TestGyp(formats=['make'])
+
+# We want our Makefile to be one dir up from main.gyp.
+test.run_gyp('main.gyp', '--toplevel-dir=..', chdir='src/sub1')
+
+toplevel_dir = 'src'
+
+test.build('all', chdir=toplevel_dir)
+
+test.built_file_must_exist('prog1', type=test.EXECUTABLE, chdir=toplevel_dir)
+
+test.run_built_executable('prog1',
+ chdir=toplevel_dir,
+ stdout="Hello from prog1.c\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/toplevel-dir/src/sub1/main.gyp b/Source/ThirdParty/gyp/test/toplevel-dir/src/sub1/main.gyp
new file mode 100644
index 000000000..33219010e
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toplevel-dir/src/sub1/main.gyp
@@ -0,0 +1,18 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'prog1',
+ 'type': 'executable',
+ 'dependencies': [
+ '<(DEPTH)/../sub2/prog2.gyp:prog2',
+ ],
+ 'sources': [
+ 'prog1.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/toplevel-dir/src/sub1/prog1.c b/Source/ThirdParty/gyp/test/toplevel-dir/src/sub1/prog1.c
new file mode 100644
index 000000000..161ae8a38
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toplevel-dir/src/sub1/prog1.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog1.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/toplevel-dir/src/sub2/prog2.c b/Source/ThirdParty/gyp/test/toplevel-dir/src/sub2/prog2.c
new file mode 100644
index 000000000..7635ae8c1
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toplevel-dir/src/sub2/prog2.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ printf("Hello from prog2.c\n");
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/toplevel-dir/src/sub2/prog2.gyp b/Source/ThirdParty/gyp/test/toplevel-dir/src/sub2/prog2.gyp
new file mode 100644
index 000000000..593454836
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/toplevel-dir/src/sub2/prog2.gyp
@@ -0,0 +1,15 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'prog2',
+ 'type': 'executable',
+ 'sources': [
+ 'prog2.c',
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gyp b/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gyp
new file mode 100644
index 000000000..822ae4f05
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gyp
@@ -0,0 +1,128 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a simple test file to make sure that variable substitution
+# happens correctly. Run "run_tests.py" using python to generate the
+# output from this gyp file.
+
+{
+ 'variables': {
+ 'pi': 'import math; print math.pi',
+ 'third_letters': "<(other_letters)HIJK",
+ 'letters_list': 'ABCD',
+ 'other_letters': '<(letters_list)EFG',
+ 'check_included': '<(included_variable)',
+ 'check_lists': [
+ '<(included_variable)',
+ '<(third_letters)',
+ ],
+ 'check_int': 5,
+ 'check_str_int': '6',
+ 'check_list_int': [
+ 7,
+ '8',
+ 9,
+ ],
+ 'not_int_1': ' 10',
+ 'not_int_2': '11 ',
+ 'not_int_3': '012',
+ 'not_int_4': '13.0',
+ 'not_int_5': '+14',
+ 'negative_int': '-15',
+ 'zero_int': '0',
+ },
+ 'includes': [
+ 'commands.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'none',
+ 'variables': {
+ 'var1': '<!(["python", "-c", "<(pi)"])',
+ 'var2': '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")',
+ 'var3': '<!(python -c "print \'<(letters_list)\'")',
+ 'var4': '<(<!(python -c "print \'letters_list\'"))',
+ 'var5': 'letters_',
+ 'var6': 'list',
+ 'var7': '<(check_int)',
+ 'var8': '<(check_int)blah',
+ 'var9': '<(check_str_int)',
+ 'var10': '<(check_list_int)',
+ 'var11': ['<@(check_list_int)'],
+ 'var12': '<(not_int_1)',
+ 'var13': '<(not_int_2)',
+ 'var14': '<(not_int_3)',
+ 'var15': '<(not_int_4)',
+ 'var16': '<(not_int_5)',
+ 'var17': '<(negative_int)',
+ 'var18': '<(zero_int)',
+ # A second set with different names to make sure they only execute the
+ # commands once.
+ 'var1prime': '<!(["python", "-c", "<(pi)"])',
+ 'var2prime': '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")',
+ 'var3prime': '<!(python -c "print \'<(letters_list)\'")',
+ 'var4prime': '<(<!(python -c "print \'letters_list\'"))',
+ },
+ 'actions': [
+ {
+ 'action_name': 'test_action',
+ 'variables': {
+ 'var7': '<!(echo <(var5)<(var6))',
+ },
+ 'inputs' : [
+ '<(var2)',
+ ],
+ 'outputs': [
+ '<(var4)',
+ '<(var7)',
+ ],
+ 'action': [
+ 'echo',
+ '<(_inputs)',
+ '<(_outputs)',
+ ],
+ },
+ # Again with the same vars to make sure the right things happened.
+ {
+ 'action_name': 'test_action_prime',
+ 'variables': {
+ 'var7': '<!(echo <(var5)<(var6))',
+ },
+ 'inputs' : [
+ '<(var2)',
+ ],
+ 'outputs': [
+ '<(var4)',
+ '<(var7)',
+ ],
+ 'action': [
+ 'echo',
+ '<(_inputs)',
+ '<(_outputs)',
+ ],
+ },
+ # And one more time with the other vars...
+ {
+ 'action_name': 'test_action_prime_prime',
+ 'variables': {
+ 'var7': '<!(echo <(var5)<(var6))',
+ },
+ 'inputs' : [
+ '<(var2prime)',
+ ],
+ 'outputs': [
+ '<(var4prime)',
+ '<(var7)',
+ ],
+ 'action': [
+ 'echo',
+ '<(_inputs)',
+ '<(_outputs)',
+ ],
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gyp.stdout b/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gyp.stdout
new file mode 100644
index 000000000..6cbe797fd
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gyp.stdout
@@ -0,0 +1,405 @@
+GENERAL: running with these options:
+GENERAL: check: None
+GENERAL: circular_check: True
+GENERAL: debug: ['variables', 'general']
+GENERAL: defines: None
+GENERAL: depth: '.'
+GENERAL: formats: ['gypd']
+GENERAL: generator_flags: []
+GENERAL: generator_output: None
+GENERAL: includes: None
+GENERAL: msvs_version: None
+GENERAL: suffix: ''
+GENERAL: toplevel_dir: None
+GENERAL: use_environment: True
+GENERAL: cmdline_default_variables: {}
+GENERAL: generator_flags: {}
+VARIABLES: Expanding '0' to 0
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '-15' to -15
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFG', recursing.
+VARIABLES: Expanding 'ABCDEFG' to 'ABCDEFG'
+VARIABLES: Expanding '<(letters_list)EFG' to 'ABCDEFG'
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Matches: {'content': 'other_letters', 'is_array': '', 'type': '<', 'replace': '<(other_letters)'}
+VARIABLES: Expanding 'other_letters' to 'other_letters'
+VARIABLES: Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFGHIJK', recursing.
+VARIABLES: Expanding 'ABCDEFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(letters_list)EFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(other_letters)HIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding 'import math; print math.pi' to 'import math; print math.pi'
+VARIABLES: Matches: {'content': 'included_variable', 'is_array': '', 'type': '<', 'replace': '<(included_variable)'}
+VARIABLES: Expanding 'included_variable' to 'included_variable'
+VARIABLES: Found output 'XYZ', recursing.
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding '<(included_variable)' to 'XYZ'
+VARIABLES: Expanding '6' to 6
+VARIABLES: Matches: {'content': 'included_variable', 'is_array': '', 'type': '<', 'replace': '<(included_variable)'}
+VARIABLES: Expanding 'included_variable' to 'included_variable'
+VARIABLES: Found output 'XYZ', recursing.
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding '<(included_variable)' to 'XYZ'
+VARIABLES: Matches: {'content': 'third_letters', 'is_array': '', 'type': '<', 'replace': '<(third_letters)'}
+VARIABLES: Expanding 'third_letters' to 'third_letters'
+VARIABLES: Found output '<(other_letters)HIJK', recursing.
+VARIABLES: Matches: {'content': 'other_letters', 'is_array': '', 'type': '<', 'replace': '<(other_letters)'}
+VARIABLES: Expanding 'other_letters' to 'other_letters'
+VARIABLES: Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFGHIJK', recursing.
+VARIABLES: Expanding 'ABCDEFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(letters_list)EFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(other_letters)HIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(third_letters)' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '8' to 8
+VARIABLES: Expanding '.' to '.'
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'<!(python -c "<(pi)'}
+VARIABLES: Matches: {'content': 'python -c "<(pi', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "<(pi)'}
+VARIABLES: Matches: {'content': 'pi', 'is_array': '', 'type': '<', 'replace': '<(pi)'}
+VARIABLES: Expanding 'pi' to 'pi'
+VARIABLES: Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES: Expanding 'python -c "import math; print math.pi"' to 'python -c "import math; print math.pi"'
+VARIABLES: Expanding 'python -c "<(pi)"' to 'python -c "import math; print math.pi"'
+VARIABLES: Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES: Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES: Expanding 'python -c "print \'3.14159265359 ABCD\'"' to 'python -c "print \'3.14159265359 ABCD\'"'
+VARIABLES: Expanding 'python -c "print \'<!(python -c "<(pi)") ABCD\'"' to 'python -c "print \'3.14159265359 ABCD\'"'
+VARIABLES: Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")' to '3.14159265359 ABCD'
+VARIABLES: Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'type': '<!', 'replace': '<!(["python", "-c", "<(pi)'}
+VARIABLES: Matches: {'content': 'pi', 'is_array': '', 'type': '<', 'replace': '<(pi)'}
+VARIABLES: Expanding 'pi' to 'pi'
+VARIABLES: Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES: Expanding '["python", "-c", "import math; print math.pi"]' to '["python", "-c", "import math; print math.pi"]'
+VARIABLES: Expanding '["python", "-c", "<(pi)"]' to '["python", "-c", "import math; print math.pi"]'
+VARIABLES: Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES: Found output '3.14159265359', recursing.
+VARIABLES: Expanding '3.14159265359' to '3.14159265359'
+VARIABLES: Expanding '<!(["python", "-c", "<(pi)"])' to '3.14159265359'
+VARIABLES: Expanding 'letters_' to 'letters_'
+VARIABLES: Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'type': '<', 'replace': '<(<!(python -c "print \'letters_list\'")'}
+VARIABLES: Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'letters_list\'")'}
+VARIABLES: Expanding 'python -c "print \'letters_list\'"' to 'python -c "print \'letters_list\'"'
+VARIABLES: Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(python -c "print \'letters_list\'")' to 'letters_list'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(<!(python -c "print \'letters_list\'"))' to 'ABCD'
+VARIABLES: Matches: {'content': 'check_int', 'is_array': '', 'type': '<', 'replace': '<(check_int)'}
+VARIABLES: Expanding 'check_int' to 'check_int'
+VARIABLES: Found output '5', recursing.
+VARIABLES: Expanding '5' to 5
+VARIABLES: Expanding '<(check_int)' to 5
+VARIABLES: Expanding 'list' to 'list'
+VARIABLES: Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'type': '<!', 'replace': '<!(["python", "-c", "<(pi)'}
+VARIABLES: Matches: {'content': 'pi', 'is_array': '', 'type': '<', 'replace': '<(pi)'}
+VARIABLES: Expanding 'pi' to 'pi'
+VARIABLES: Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES: Expanding '["python", "-c", "import math; print math.pi"]' to '["python", "-c", "import math; print math.pi"]'
+VARIABLES: Expanding '["python", "-c", "<(pi)"]' to '["python", "-c", "import math; print math.pi"]'
+VARIABLES: Had cache value for command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES: Found output '3.14159265359', recursing.
+VARIABLES: Expanding '3.14159265359' to '3.14159265359'
+VARIABLES: Expanding '<!(["python", "-c", "<(pi)"])' to '3.14159265359'
+VARIABLES: Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'<(letters_list)'}
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES: Expanding 'python -c "print \'ABCD\'"' to 'python -c "print \'ABCD\'"'
+VARIABLES: Expanding 'python -c "print \'<(letters_list)\'"' to 'python -c "print \'ABCD\'"'
+VARIABLES: Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<!(python -c "print \'<(letters_list)\'")' to 'ABCD'
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'<!(python -c "<(pi)'}
+VARIABLES: Matches: {'content': 'python -c "<(pi', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "<(pi)'}
+VARIABLES: Matches: {'content': 'pi', 'is_array': '', 'type': '<', 'replace': '<(pi)'}
+VARIABLES: Expanding 'pi' to 'pi'
+VARIABLES: Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES: Expanding 'python -c "import math; print math.pi"' to 'python -c "import math; print math.pi"'
+VARIABLES: Expanding 'python -c "<(pi)"' to 'python -c "import math; print math.pi"'
+VARIABLES: Had cache value for command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES: Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES: Expanding 'python -c "print \'3.14159265359 ABCD\'"' to 'python -c "print \'3.14159265359 ABCD\'"'
+VARIABLES: Expanding 'python -c "print \'<!(python -c "<(pi)") ABCD\'"' to 'python -c "print \'3.14159265359 ABCD\'"'
+VARIABLES: Had cache value for command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")' to '3.14159265359 ABCD'
+VARIABLES: Matches: {'content': 'check_str_int', 'is_array': '', 'type': '<', 'replace': '<(check_str_int)'}
+VARIABLES: Expanding 'check_str_int' to 'check_str_int'
+VARIABLES: Found output '6', recursing.
+VARIABLES: Expanding '6' to 6
+VARIABLES: Expanding '<(check_str_int)' to 6
+VARIABLES: Matches: {'content': 'check_int', 'is_array': '', 'type': '<', 'replace': '<(check_int)'}
+VARIABLES: Expanding 'check_int' to 'check_int'
+VARIABLES: Found output '5blah', recursing.
+VARIABLES: Expanding '5blah' to '5blah'
+VARIABLES: Expanding '<(check_int)blah' to '5blah'
+VARIABLES: Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'type': '<', 'replace': '<(<!(python -c "print \'letters_list\'")'}
+VARIABLES: Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'letters_list\'")'}
+VARIABLES: Expanding 'python -c "print \'letters_list\'"' to 'python -c "print \'letters_list\'"'
+VARIABLES: Had cache value for command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(python -c "print \'letters_list\'")' to 'letters_list'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(<!(python -c "print \'letters_list\'"))' to 'ABCD'
+VARIABLES: Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'<(letters_list)'}
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES: Expanding 'python -c "print \'ABCD\'"' to 'python -c "print \'ABCD\'"'
+VARIABLES: Expanding 'python -c "print \'<(letters_list)\'"' to 'python -c "print \'ABCD\'"'
+VARIABLES: Had cache value for command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<!(python -c "print \'<(letters_list)\'")' to 'ABCD'
+VARIABLES: Matches: {'content': 'not_int_4', 'is_array': '', 'type': '<', 'replace': '<(not_int_4)'}
+VARIABLES: Expanding 'not_int_4' to 'not_int_4'
+VARIABLES: Found output '13.0', recursing.
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding '<(not_int_4)' to '13.0'
+VARIABLES: Matches: {'content': 'not_int_3', 'is_array': '', 'type': '<', 'replace': '<(not_int_3)'}
+VARIABLES: Expanding 'not_int_3' to 'not_int_3'
+VARIABLES: Found output '012', recursing.
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Expanding '<(not_int_3)' to '012'
+VARIABLES: Matches: {'content': 'negative_int', 'is_array': '', 'type': '<', 'replace': '<(negative_int)'}
+VARIABLES: Expanding 'negative_int' to 'negative_int'
+VARIABLES: Found output '-15', recursing.
+VARIABLES: Expanding '-15' to -15
+VARIABLES: Expanding '<(negative_int)' to -15
+VARIABLES: Matches: {'content': 'not_int_5', 'is_array': '', 'type': '<', 'replace': '<(not_int_5)'}
+VARIABLES: Expanding 'not_int_5' to 'not_int_5'
+VARIABLES: Found output '+14', recursing.
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '<(not_int_5)' to '+14'
+VARIABLES: Matches: {'content': 'check_list_int', 'is_array': '', 'type': '<', 'replace': '<(check_list_int)'}
+VARIABLES: Expanding 'check_list_int' to 'check_list_int'
+VARIABLES: Found output '7 8 9', recursing.
+VARIABLES: Expanding '7 8 9' to '7 8 9'
+VARIABLES: Expanding '<(check_list_int)' to '7 8 9'
+VARIABLES: Matches: {'content': 'not_int_2', 'is_array': '', 'type': '<', 'replace': '<(not_int_2)'}
+VARIABLES: Expanding 'not_int_2' to 'not_int_2'
+VARIABLES: Found output '11 ', recursing.
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding '<(not_int_2)' to '11 '
+VARIABLES: Matches: {'content': 'not_int_1', 'is_array': '', 'type': '<', 'replace': '<(not_int_1)'}
+VARIABLES: Expanding 'not_int_1' to 'not_int_1'
+VARIABLES: Found output ' 10', recursing.
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Expanding '<(not_int_1)' to ' 10'
+VARIABLES: Matches: {'content': 'zero_int', 'is_array': '', 'type': '<', 'replace': '<(zero_int)'}
+VARIABLES: Expanding 'zero_int' to 'zero_int'
+VARIABLES: Found output '0', recursing.
+VARIABLES: Expanding '0' to 0
+VARIABLES: Expanding '<(zero_int)' to 0
+VARIABLES: Matches: {'content': 'check_list_int', 'is_array': '', 'type': '<@', 'replace': '<@(check_list_int)'}
+VARIABLES: Expanding 'check_list_int' to 'check_list_int'
+VARIABLES: Found output [7, 8, 9], recursing.
+VARIABLES: Expanding 7 to 7
+VARIABLES: Expanding 8 to 8
+VARIABLES: Expanding 9 to 9
+VARIABLES: Expanding '<@(check_list_int)' to [7, 8, 9]
+VARIABLES: Expanding 'foo' to 'foo'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Matches: {'content': 'var6', 'is_array': '', 'type': '<', 'replace': '<(var6)'}
+VARIABLES: Expanding 'var6' to 'var6'
+VARIABLES: Matches: {'content': 'echo <(var5', 'is_array': '', 'type': '<!', 'replace': '<!(echo <(var5)'}
+VARIABLES: Matches: {'content': 'var5', 'is_array': '', 'type': '<', 'replace': '<(var5)'}
+VARIABLES: Expanding 'var5' to 'var5'
+VARIABLES: Found output 'echo letters_list', recursing.
+VARIABLES: Expanding 'echo letters_list' to 'echo letters_list'
+VARIABLES: Expanding 'echo <(var5)list' to 'echo letters_list'
+VARIABLES: Executing command 'echo letters_list' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(echo <(var5)<(var6))' to 'letters_list'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Matches: {'content': '_inputs', 'is_array': '', 'type': '<', 'replace': '<(_inputs)'}
+VARIABLES: Expanding '_inputs' to '_inputs'
+VARIABLES: Matches: {'content': 'var2', 'is_array': '', 'type': '<', 'replace': '<(var2)'}
+VARIABLES: Expanding 'var2' to 'var2'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<(var2)' to '3.14159265359 ABCD'
+VARIABLES: Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding '<(_inputs)' to '"3.14159265359 ABCD"'
+VARIABLES: Matches: {'content': '_outputs', 'is_array': '', 'type': '<', 'replace': '<(_outputs)'}
+VARIABLES: Expanding '_outputs' to '_outputs'
+VARIABLES: Matches: {'content': 'var4', 'is_array': '', 'type': '<', 'replace': '<(var4)'}
+VARIABLES: Expanding 'var4' to 'var4'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(var4)' to 'ABCD'
+VARIABLES: Matches: {'content': 'var7', 'is_array': '', 'type': '<', 'replace': '<(var7)'}
+VARIABLES: Expanding 'var7' to 'var7'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<(var7)' to 'letters_list'
+VARIABLES: Found output 'ABCD letters_list', recursing.
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '<(_outputs)' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Matches: {'content': 'var6', 'is_array': '', 'type': '<', 'replace': '<(var6)'}
+VARIABLES: Expanding 'var6' to 'var6'
+VARIABLES: Matches: {'content': 'echo <(var5', 'is_array': '', 'type': '<!', 'replace': '<!(echo <(var5)'}
+VARIABLES: Matches: {'content': 'var5', 'is_array': '', 'type': '<', 'replace': '<(var5)'}
+VARIABLES: Expanding 'var5' to 'var5'
+VARIABLES: Found output 'echo letters_list', recursing.
+VARIABLES: Expanding 'echo letters_list' to 'echo letters_list'
+VARIABLES: Expanding 'echo <(var5)list' to 'echo letters_list'
+VARIABLES: Had cache value for command 'echo letters_list' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(echo <(var5)<(var6))' to 'letters_list'
+VARIABLES: Expanding 'test_action_prime' to 'test_action_prime'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Matches: {'content': '_inputs', 'is_array': '', 'type': '<', 'replace': '<(_inputs)'}
+VARIABLES: Expanding '_inputs' to '_inputs'
+VARIABLES: Matches: {'content': 'var2', 'is_array': '', 'type': '<', 'replace': '<(var2)'}
+VARIABLES: Expanding 'var2' to 'var2'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<(var2)' to '3.14159265359 ABCD'
+VARIABLES: Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding '<(_inputs)' to '"3.14159265359 ABCD"'
+VARIABLES: Matches: {'content': '_outputs', 'is_array': '', 'type': '<', 'replace': '<(_outputs)'}
+VARIABLES: Expanding '_outputs' to '_outputs'
+VARIABLES: Matches: {'content': 'var4', 'is_array': '', 'type': '<', 'replace': '<(var4)'}
+VARIABLES: Expanding 'var4' to 'var4'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(var4)' to 'ABCD'
+VARIABLES: Matches: {'content': 'var7', 'is_array': '', 'type': '<', 'replace': '<(var7)'}
+VARIABLES: Expanding 'var7' to 'var7'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<(var7)' to 'letters_list'
+VARIABLES: Found output 'ABCD letters_list', recursing.
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '<(_outputs)' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Matches: {'content': 'var6', 'is_array': '', 'type': '<', 'replace': '<(var6)'}
+VARIABLES: Expanding 'var6' to 'var6'
+VARIABLES: Matches: {'content': 'echo <(var5', 'is_array': '', 'type': '<!', 'replace': '<!(echo <(var5)'}
+VARIABLES: Matches: {'content': 'var5', 'is_array': '', 'type': '<', 'replace': '<(var5)'}
+VARIABLES: Expanding 'var5' to 'var5'
+VARIABLES: Found output 'echo letters_list', recursing.
+VARIABLES: Expanding 'echo letters_list' to 'echo letters_list'
+VARIABLES: Expanding 'echo <(var5)list' to 'echo letters_list'
+VARIABLES: Had cache value for command 'echo letters_list' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(echo <(var5)<(var6))' to 'letters_list'
+VARIABLES: Expanding 'test_action_prime_prime' to 'test_action_prime_prime'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Matches: {'content': '_inputs', 'is_array': '', 'type': '<', 'replace': '<(_inputs)'}
+VARIABLES: Expanding '_inputs' to '_inputs'
+VARIABLES: Matches: {'content': 'var2prime', 'is_array': '', 'type': '<', 'replace': '<(var2prime)'}
+VARIABLES: Expanding 'var2prime' to 'var2prime'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<(var2prime)' to '3.14159265359 ABCD'
+VARIABLES: Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding '<(_inputs)' to '"3.14159265359 ABCD"'
+VARIABLES: Matches: {'content': '_outputs', 'is_array': '', 'type': '<', 'replace': '<(_outputs)'}
+VARIABLES: Expanding '_outputs' to '_outputs'
+VARIABLES: Matches: {'content': 'var4prime', 'is_array': '', 'type': '<', 'replace': '<(var4prime)'}
+VARIABLES: Expanding 'var4prime' to 'var4prime'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(var4prime)' to 'ABCD'
+VARIABLES: Matches: {'content': 'var7', 'is_array': '', 'type': '<', 'replace': '<(var7)'}
+VARIABLES: Expanding 'var7' to 'var7'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<(var7)' to 'letters_list'
+VARIABLES: Found output 'ABCD letters_list', recursing.
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '<(_outputs)' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'dummy' to 'dummy'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'commands-repeated.gyp' to 'commands-repeated.gyp'
+VARIABLES: Expanding 'commands.gypi' to 'commands.gypi'
+VARIABLES: Expanding 'dummy' to 'dummy'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '3.14159265359' to '3.14159265359'
+VARIABLES: Expanding 'letters_' to 'letters_'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'list' to 'list'
+VARIABLES: Expanding '3.14159265359' to '3.14159265359'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '5blah' to '5blah'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '7 8 9' to '7 8 9'
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Expanding 'foo' to 'foo'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'test_action_prime' to 'test_action_prime'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'test_action_prime_prime' to 'test_action_prime_prime'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
diff --git a/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gypd.golden b/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gypd.golden
new file mode 100644
index 000000000..96615b663
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/commands-repeated.gypd.golden
@@ -0,0 +1,72 @@
+{'_DEPTH': '.',
+ 'included_files': ['commands-repeated.gyp', 'commands.gypi'],
+ 'targets': [{'actions': [{'action': ['echo',
+ '"3.14159265359 ABCD"',
+ 'ABCD letters_list'],
+ 'action_name': 'test_action',
+ 'inputs': ['3.14159265359 ABCD'],
+ 'outputs': ['ABCD', 'letters_list'],
+ 'variables': {'var7': 'letters_list'}},
+ {'action': ['echo',
+ '"3.14159265359 ABCD"',
+ 'ABCD letters_list'],
+ 'action_name': 'test_action_prime',
+ 'inputs': ['3.14159265359 ABCD'],
+ 'outputs': ['ABCD', 'letters_list'],
+ 'variables': {'var7': 'letters_list'}},
+ {'action': ['echo',
+ '"3.14159265359 ABCD"',
+ 'ABCD letters_list'],
+ 'action_name': 'test_action_prime_prime',
+ 'inputs': ['3.14159265359 ABCD'],
+ 'outputs': ['ABCD', 'letters_list'],
+ 'variables': {'var7': 'letters_list'}}],
+ 'configurations': {'Default': {}},
+ 'default_configuration': 'Default',
+ 'target_name': 'foo',
+ 'toolset': 'target',
+ 'type': 'none',
+ 'variables': {'var1': '3.14159265359',
+ 'var10': '7 8 9',
+ 'var11': ['7', '8', '9'],
+ 'var12': ' 10',
+ 'var13': '11 ',
+ 'var14': '012',
+ 'var15': '13.0',
+ 'var16': '+14',
+ 'var17': '-15',
+ 'var18': '0',
+ 'var1prime': '3.14159265359',
+ 'var2': '3.14159265359 ABCD',
+ 'var2prime': '3.14159265359 ABCD',
+ 'var3': 'ABCD',
+ 'var3prime': 'ABCD',
+ 'var4': 'ABCD',
+ 'var4prime': 'ABCD',
+ 'var5': 'letters_',
+ 'var6': 'list',
+ 'var7': '5',
+ 'var8': '5blah',
+ 'var9': '6'}},
+ {'configurations': {'Default': {}},
+ 'default_configuration': 'Default',
+ 'target_name': 'dummy',
+ 'toolset': 'target',
+ 'type': 'none'}],
+ 'variables': {'check_included': 'XYZ',
+ 'check_int': '5',
+ 'check_list_int': ['7', '8', '9'],
+ 'check_lists': ['XYZ', 'ABCDEFGHIJK'],
+ 'check_str_int': '6',
+ 'included_variable': 'XYZ',
+ 'letters_list': 'ABCD',
+ 'negative_int': '-15',
+ 'not_int_1': ' 10',
+ 'not_int_2': '11 ',
+ 'not_int_3': '012',
+ 'not_int_4': '13.0',
+ 'not_int_5': '+14',
+ 'other_letters': 'ABCDEFG',
+ 'pi': 'import math; print math.pi',
+ 'third_letters': 'ABCDEFGHIJK',
+ 'zero_int': '0'}}
diff --git a/Source/ThirdParty/gyp/test/variables/commands/commands.gyp b/Source/ThirdParty/gyp/test/variables/commands/commands.gyp
new file mode 100644
index 000000000..113e4a279
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/commands.gyp
@@ -0,0 +1,84 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a simple test file to make sure that variable substitution
+# happens correctly. Run "run_tests.py" using python to generate the
+# output from this gyp file.
+
+{
+ 'variables': {
+ 'pi': 'import math; print math.pi',
+ 'third_letters': "<(other_letters)HIJK",
+ 'letters_list': 'ABCD',
+ 'other_letters': '<(letters_list)EFG',
+ 'check_included': '<(included_variable)',
+ 'check_lists': [
+ '<(included_variable)',
+ '<(third_letters)',
+ ],
+ 'check_int': 5,
+ 'check_str_int': '6',
+ 'check_list_int': [
+ 7,
+ '8',
+ 9,
+ ],
+ 'not_int_1': ' 10',
+ 'not_int_2': '11 ',
+ 'not_int_3': '012',
+ 'not_int_4': '13.0',
+ 'not_int_5': '+14',
+ 'negative_int': '-15',
+ 'zero_int': '0',
+ },
+ 'includes': [
+ 'commands.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'none',
+ 'variables': {
+ 'var1': '<!(["python", "-c", "<(pi)"])',
+ 'var2': '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")',
+ 'var3': '<!(python -c "print \'<(letters_list)\'")',
+ 'var4': '<(<!(python -c "print \'letters_list\'"))',
+ 'var5': 'letters_',
+ 'var6': 'list',
+ 'var7': '<(check_int)',
+ 'var8': '<(check_int)blah',
+ 'var9': '<(check_str_int)',
+ 'var10': '<(check_list_int)',
+ 'var11': ['<@(check_list_int)'],
+ 'var12': '<(not_int_1)',
+ 'var13': '<(not_int_2)',
+ 'var14': '<(not_int_3)',
+ 'var15': '<(not_int_4)',
+ 'var16': '<(not_int_5)',
+ 'var17': '<(negative_int)',
+ 'var18': '<(zero_int)',
+ },
+ 'actions': [
+ {
+ 'action_name': 'test_action',
+ 'variables': {
+ 'var7': '<!(echo <(var5)<(var6))',
+ },
+ 'inputs' : [
+ '<(var2)',
+ ],
+ 'outputs': [
+ '<(var4)',
+ '<(var7)',
+ ],
+ 'action': [
+ 'echo',
+ '<(_inputs)',
+ '<(_outputs)',
+ ],
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/variables/commands/commands.gyp.ignore-env.stdout b/Source/ThirdParty/gyp/test/variables/commands/commands.gyp.ignore-env.stdout
new file mode 100644
index 000000000..7f7df790d
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/commands.gyp.ignore-env.stdout
@@ -0,0 +1,254 @@
+GENERAL: running with these options:
+GENERAL: check: None
+GENERAL: circular_check: True
+GENERAL: debug: ['variables', 'general']
+GENERAL: defines: None
+GENERAL: depth: '.'
+GENERAL: formats: ['gypd']
+GENERAL: generator_flags: []
+GENERAL: generator_output: None
+GENERAL: includes: None
+GENERAL: msvs_version: None
+GENERAL: suffix: ''
+GENERAL: toplevel_dir: None
+GENERAL: use_environment: False
+GENERAL: cmdline_default_variables: {}
+GENERAL: generator_flags: {}
+VARIABLES: Expanding '0' to 0
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '-15' to -15
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFG', recursing.
+VARIABLES: Expanding 'ABCDEFG' to 'ABCDEFG'
+VARIABLES: Expanding '<(letters_list)EFG' to 'ABCDEFG'
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Matches: {'content': 'other_letters', 'is_array': '', 'type': '<', 'replace': '<(other_letters)'}
+VARIABLES: Expanding 'other_letters' to 'other_letters'
+VARIABLES: Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFGHIJK', recursing.
+VARIABLES: Expanding 'ABCDEFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(letters_list)EFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(other_letters)HIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding 'import math; print math.pi' to 'import math; print math.pi'
+VARIABLES: Matches: {'content': 'included_variable', 'is_array': '', 'type': '<', 'replace': '<(included_variable)'}
+VARIABLES: Expanding 'included_variable' to 'included_variable'
+VARIABLES: Found output 'XYZ', recursing.
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding '<(included_variable)' to 'XYZ'
+VARIABLES: Expanding '6' to 6
+VARIABLES: Matches: {'content': 'included_variable', 'is_array': '', 'type': '<', 'replace': '<(included_variable)'}
+VARIABLES: Expanding 'included_variable' to 'included_variable'
+VARIABLES: Found output 'XYZ', recursing.
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding '<(included_variable)' to 'XYZ'
+VARIABLES: Matches: {'content': 'third_letters', 'is_array': '', 'type': '<', 'replace': '<(third_letters)'}
+VARIABLES: Expanding 'third_letters' to 'third_letters'
+VARIABLES: Found output '<(other_letters)HIJK', recursing.
+VARIABLES: Matches: {'content': 'other_letters', 'is_array': '', 'type': '<', 'replace': '<(other_letters)'}
+VARIABLES: Expanding 'other_letters' to 'other_letters'
+VARIABLES: Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFGHIJK', recursing.
+VARIABLES: Expanding 'ABCDEFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(letters_list)EFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(other_letters)HIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(third_letters)' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '8' to 8
+VARIABLES: Expanding '.' to '.'
+VARIABLES: Expanding 'letters_' to 'letters_'
+VARIABLES: Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'type': '<', 'replace': '<(<!(python -c "print \'letters_list\'")'}
+VARIABLES: Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'letters_list\'")'}
+VARIABLES: Expanding 'python -c "print \'letters_list\'"' to 'python -c "print \'letters_list\'"'
+VARIABLES: Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(python -c "print \'letters_list\'")' to 'letters_list'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(<!(python -c "print \'letters_list\'"))' to 'ABCD'
+VARIABLES: Matches: {'content': 'check_int', 'is_array': '', 'type': '<', 'replace': '<(check_int)'}
+VARIABLES: Expanding 'check_int' to 'check_int'
+VARIABLES: Found output '5', recursing.
+VARIABLES: Expanding '5' to 5
+VARIABLES: Expanding '<(check_int)' to 5
+VARIABLES: Expanding 'list' to 'list'
+VARIABLES: Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'type': '<!', 'replace': '<!(["python", "-c", "<(pi)'}
+VARIABLES: Matches: {'content': 'pi', 'is_array': '', 'type': '<', 'replace': '<(pi)'}
+VARIABLES: Expanding 'pi' to 'pi'
+VARIABLES: Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES: Expanding '["python", "-c", "import math; print math.pi"]' to '["python", "-c", "import math; print math.pi"]'
+VARIABLES: Expanding '["python", "-c", "<(pi)"]' to '["python", "-c", "import math; print math.pi"]'
+VARIABLES: Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES: Found output '3.14159265359', recursing.
+VARIABLES: Expanding '3.14159265359' to '3.14159265359'
+VARIABLES: Expanding '<!(["python", "-c", "<(pi)"])' to '3.14159265359'
+VARIABLES: Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'<(letters_list)'}
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES: Expanding 'python -c "print \'ABCD\'"' to 'python -c "print \'ABCD\'"'
+VARIABLES: Expanding 'python -c "print \'<(letters_list)\'"' to 'python -c "print \'ABCD\'"'
+VARIABLES: Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<!(python -c "print \'<(letters_list)\'")' to 'ABCD'
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'<!(python -c "<(pi)'}
+VARIABLES: Matches: {'content': 'python -c "<(pi', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "<(pi)'}
+VARIABLES: Matches: {'content': 'pi', 'is_array': '', 'type': '<', 'replace': '<(pi)'}
+VARIABLES: Expanding 'pi' to 'pi'
+VARIABLES: Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES: Expanding 'python -c "import math; print math.pi"' to 'python -c "import math; print math.pi"'
+VARIABLES: Expanding 'python -c "<(pi)"' to 'python -c "import math; print math.pi"'
+VARIABLES: Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES: Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES: Expanding 'python -c "print \'3.14159265359 ABCD\'"' to 'python -c "print \'3.14159265359 ABCD\'"'
+VARIABLES: Expanding 'python -c "print \'<!(python -c "<(pi)") ABCD\'"' to 'python -c "print \'3.14159265359 ABCD\'"'
+VARIABLES: Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")' to '3.14159265359 ABCD'
+VARIABLES: Matches: {'content': 'check_str_int', 'is_array': '', 'type': '<', 'replace': '<(check_str_int)'}
+VARIABLES: Expanding 'check_str_int' to 'check_str_int'
+VARIABLES: Found output '6', recursing.
+VARIABLES: Expanding '6' to 6
+VARIABLES: Expanding '<(check_str_int)' to 6
+VARIABLES: Matches: {'content': 'check_int', 'is_array': '', 'type': '<', 'replace': '<(check_int)'}
+VARIABLES: Expanding 'check_int' to 'check_int'
+VARIABLES: Found output '5blah', recursing.
+VARIABLES: Expanding '5blah' to '5blah'
+VARIABLES: Expanding '<(check_int)blah' to '5blah'
+VARIABLES: Matches: {'content': 'not_int_4', 'is_array': '', 'type': '<', 'replace': '<(not_int_4)'}
+VARIABLES: Expanding 'not_int_4' to 'not_int_4'
+VARIABLES: Found output '13.0', recursing.
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding '<(not_int_4)' to '13.0'
+VARIABLES: Matches: {'content': 'not_int_3', 'is_array': '', 'type': '<', 'replace': '<(not_int_3)'}
+VARIABLES: Expanding 'not_int_3' to 'not_int_3'
+VARIABLES: Found output '012', recursing.
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Expanding '<(not_int_3)' to '012'
+VARIABLES: Matches: {'content': 'negative_int', 'is_array': '', 'type': '<', 'replace': '<(negative_int)'}
+VARIABLES: Expanding 'negative_int' to 'negative_int'
+VARIABLES: Found output '-15', recursing.
+VARIABLES: Expanding '-15' to -15
+VARIABLES: Expanding '<(negative_int)' to -15
+VARIABLES: Matches: {'content': 'not_int_5', 'is_array': '', 'type': '<', 'replace': '<(not_int_5)'}
+VARIABLES: Expanding 'not_int_5' to 'not_int_5'
+VARIABLES: Found output '+14', recursing.
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '<(not_int_5)' to '+14'
+VARIABLES: Matches: {'content': 'check_list_int', 'is_array': '', 'type': '<', 'replace': '<(check_list_int)'}
+VARIABLES: Expanding 'check_list_int' to 'check_list_int'
+VARIABLES: Found output '7 8 9', recursing.
+VARIABLES: Expanding '7 8 9' to '7 8 9'
+VARIABLES: Expanding '<(check_list_int)' to '7 8 9'
+VARIABLES: Matches: {'content': 'not_int_2', 'is_array': '', 'type': '<', 'replace': '<(not_int_2)'}
+VARIABLES: Expanding 'not_int_2' to 'not_int_2'
+VARIABLES: Found output '11 ', recursing.
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding '<(not_int_2)' to '11 '
+VARIABLES: Matches: {'content': 'not_int_1', 'is_array': '', 'type': '<', 'replace': '<(not_int_1)'}
+VARIABLES: Expanding 'not_int_1' to 'not_int_1'
+VARIABLES: Found output ' 10', recursing.
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Expanding '<(not_int_1)' to ' 10'
+VARIABLES: Matches: {'content': 'zero_int', 'is_array': '', 'type': '<', 'replace': '<(zero_int)'}
+VARIABLES: Expanding 'zero_int' to 'zero_int'
+VARIABLES: Found output '0', recursing.
+VARIABLES: Expanding '0' to 0
+VARIABLES: Expanding '<(zero_int)' to 0
+VARIABLES: Matches: {'content': 'check_list_int', 'is_array': '', 'type': '<@', 'replace': '<@(check_list_int)'}
+VARIABLES: Expanding 'check_list_int' to 'check_list_int'
+VARIABLES: Found output [7, 8, 9], recursing.
+VARIABLES: Expanding 7 to 7
+VARIABLES: Expanding 8 to 8
+VARIABLES: Expanding 9 to 9
+VARIABLES: Expanding '<@(check_list_int)' to [7, 8, 9]
+VARIABLES: Expanding 'foo' to 'foo'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Matches: {'content': 'var6', 'is_array': '', 'type': '<', 'replace': '<(var6)'}
+VARIABLES: Expanding 'var6' to 'var6'
+VARIABLES: Matches: {'content': 'echo <(var5', 'is_array': '', 'type': '<!', 'replace': '<!(echo <(var5)'}
+VARIABLES: Matches: {'content': 'var5', 'is_array': '', 'type': '<', 'replace': '<(var5)'}
+VARIABLES: Expanding 'var5' to 'var5'
+VARIABLES: Found output 'echo letters_list', recursing.
+VARIABLES: Expanding 'echo letters_list' to 'echo letters_list'
+VARIABLES: Expanding 'echo <(var5)list' to 'echo letters_list'
+VARIABLES: Executing command 'echo letters_list' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(echo <(var5)<(var6))' to 'letters_list'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Matches: {'content': '_inputs', 'is_array': '', 'type': '<', 'replace': '<(_inputs)'}
+VARIABLES: Expanding '_inputs' to '_inputs'
+VARIABLES: Matches: {'content': 'var2', 'is_array': '', 'type': '<', 'replace': '<(var2)'}
+VARIABLES: Expanding 'var2' to 'var2'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<(var2)' to '3.14159265359 ABCD'
+VARIABLES: Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding '<(_inputs)' to '"3.14159265359 ABCD"'
+VARIABLES: Matches: {'content': '_outputs', 'is_array': '', 'type': '<', 'replace': '<(_outputs)'}
+VARIABLES: Expanding '_outputs' to '_outputs'
+VARIABLES: Matches: {'content': 'var4', 'is_array': '', 'type': '<', 'replace': '<(var4)'}
+VARIABLES: Expanding 'var4' to 'var4'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(var4)' to 'ABCD'
+VARIABLES: Matches: {'content': 'var7', 'is_array': '', 'type': '<', 'replace': '<(var7)'}
+VARIABLES: Expanding 'var7' to 'var7'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<(var7)' to 'letters_list'
+VARIABLES: Found output 'ABCD letters_list', recursing.
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '<(_outputs)' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'dummy' to 'dummy'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'commands.gyp' to 'commands.gyp'
+VARIABLES: Expanding 'commands.gypi' to 'commands.gypi'
+VARIABLES: Expanding 'dummy' to 'dummy'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'letters_' to 'letters_'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'list' to 'list'
+VARIABLES: Expanding '3.14159265359' to '3.14159265359'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '5blah' to '5blah'
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '7 8 9' to '7 8 9'
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Expanding 'foo' to 'foo'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
diff --git a/Source/ThirdParty/gyp/test/variables/commands/commands.gyp.stdout b/Source/ThirdParty/gyp/test/variables/commands/commands.gyp.stdout
new file mode 100644
index 000000000..3db5f64d5
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/commands.gyp.stdout
@@ -0,0 +1,254 @@
+GENERAL: running with these options:
+GENERAL: check: None
+GENERAL: circular_check: True
+GENERAL: debug: ['variables', 'general']
+GENERAL: defines: None
+GENERAL: depth: '.'
+GENERAL: formats: ['gypd']
+GENERAL: generator_flags: []
+GENERAL: generator_output: None
+GENERAL: includes: None
+GENERAL: msvs_version: None
+GENERAL: suffix: ''
+GENERAL: toplevel_dir: None
+GENERAL: use_environment: True
+GENERAL: cmdline_default_variables: {}
+GENERAL: generator_flags: {}
+VARIABLES: Expanding '0' to 0
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '-15' to -15
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFG', recursing.
+VARIABLES: Expanding 'ABCDEFG' to 'ABCDEFG'
+VARIABLES: Expanding '<(letters_list)EFG' to 'ABCDEFG'
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Matches: {'content': 'other_letters', 'is_array': '', 'type': '<', 'replace': '<(other_letters)'}
+VARIABLES: Expanding 'other_letters' to 'other_letters'
+VARIABLES: Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFGHIJK', recursing.
+VARIABLES: Expanding 'ABCDEFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(letters_list)EFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(other_letters)HIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding 'import math; print math.pi' to 'import math; print math.pi'
+VARIABLES: Matches: {'content': 'included_variable', 'is_array': '', 'type': '<', 'replace': '<(included_variable)'}
+VARIABLES: Expanding 'included_variable' to 'included_variable'
+VARIABLES: Found output 'XYZ', recursing.
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding '<(included_variable)' to 'XYZ'
+VARIABLES: Expanding '6' to 6
+VARIABLES: Matches: {'content': 'included_variable', 'is_array': '', 'type': '<', 'replace': '<(included_variable)'}
+VARIABLES: Expanding 'included_variable' to 'included_variable'
+VARIABLES: Found output 'XYZ', recursing.
+VARIABLES: Expanding 'XYZ' to 'XYZ'
+VARIABLES: Expanding '<(included_variable)' to 'XYZ'
+VARIABLES: Matches: {'content': 'third_letters', 'is_array': '', 'type': '<', 'replace': '<(third_letters)'}
+VARIABLES: Expanding 'third_letters' to 'third_letters'
+VARIABLES: Found output '<(other_letters)HIJK', recursing.
+VARIABLES: Matches: {'content': 'other_letters', 'is_array': '', 'type': '<', 'replace': '<(other_letters)'}
+VARIABLES: Expanding 'other_letters' to 'other_letters'
+VARIABLES: Found output '<(letters_list)EFGHIJK', recursing.
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'ABCDEFGHIJK', recursing.
+VARIABLES: Expanding 'ABCDEFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(letters_list)EFGHIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(other_letters)HIJK' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '<(third_letters)' to 'ABCDEFGHIJK'
+VARIABLES: Expanding '8' to 8
+VARIABLES: Expanding '.' to '.'
+VARIABLES: Expanding 'letters_' to 'letters_'
+VARIABLES: Matches: {'content': '<!(python -c "print \'letters_list\'"', 'is_array': '', 'type': '<', 'replace': '<(<!(python -c "print \'letters_list\'")'}
+VARIABLES: Matches: {'content': 'python -c "print \'letters_list\'"', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'letters_list\'")'}
+VARIABLES: Expanding 'python -c "print \'letters_list\'"' to 'python -c "print \'letters_list\'"'
+VARIABLES: Executing command 'python -c "print 'letters_list'"' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(python -c "print \'letters_list\'")' to 'letters_list'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(<!(python -c "print \'letters_list\'"))' to 'ABCD'
+VARIABLES: Matches: {'content': 'check_int', 'is_array': '', 'type': '<', 'replace': '<(check_int)'}
+VARIABLES: Expanding 'check_int' to 'check_int'
+VARIABLES: Found output '5', recursing.
+VARIABLES: Expanding '5' to 5
+VARIABLES: Expanding '<(check_int)' to 5
+VARIABLES: Expanding 'list' to 'list'
+VARIABLES: Matches: {'content': '"python", "-c", "<(pi', 'is_array': '[', 'type': '<!', 'replace': '<!(["python", "-c", "<(pi)'}
+VARIABLES: Matches: {'content': 'pi', 'is_array': '', 'type': '<', 'replace': '<(pi)'}
+VARIABLES: Expanding 'pi' to 'pi'
+VARIABLES: Found output '["python", "-c", "import math; print math.pi"]', recursing.
+VARIABLES: Expanding '["python", "-c", "import math; print math.pi"]' to '["python", "-c", "import math; print math.pi"]'
+VARIABLES: Expanding '["python", "-c", "<(pi)"]' to '["python", "-c", "import math; print math.pi"]'
+VARIABLES: Executing command '['python', '-c', 'import math; print math.pi']' in directory 'None'
+VARIABLES: Found output '3.14159265359', recursing.
+VARIABLES: Expanding '3.14159265359' to '3.14159265359'
+VARIABLES: Expanding '<!(["python", "-c", "<(pi)"])' to '3.14159265359'
+VARIABLES: Matches: {'content': 'python -c "print \'<(letters_list', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'<(letters_list)'}
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Found output 'python -c "print \'ABCD\'"', recursing.
+VARIABLES: Expanding 'python -c "print \'ABCD\'"' to 'python -c "print \'ABCD\'"'
+VARIABLES: Expanding 'python -c "print \'<(letters_list)\'"' to 'python -c "print \'ABCD\'"'
+VARIABLES: Executing command 'python -c "print 'ABCD'"' in directory 'None'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<!(python -c "print \'<(letters_list)\'")' to 'ABCD'
+VARIABLES: Matches: {'content': 'letters_list', 'is_array': '', 'type': '<', 'replace': '<(letters_list)'}
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Matches: {'content': 'python -c "print \'<!(python -c "<(pi', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "print \'<!(python -c "<(pi)'}
+VARIABLES: Matches: {'content': 'python -c "<(pi', 'is_array': '', 'type': '<!', 'replace': '<!(python -c "<(pi)'}
+VARIABLES: Matches: {'content': 'pi', 'is_array': '', 'type': '<', 'replace': '<(pi)'}
+VARIABLES: Expanding 'pi' to 'pi'
+VARIABLES: Found output 'python -c "import math; print math.pi"', recursing.
+VARIABLES: Expanding 'python -c "import math; print math.pi"' to 'python -c "import math; print math.pi"'
+VARIABLES: Expanding 'python -c "<(pi)"' to 'python -c "import math; print math.pi"'
+VARIABLES: Executing command 'python -c "import math; print math.pi"' in directory 'None'
+VARIABLES: Found output 'python -c "print \'3.14159265359 ABCD\'"', recursing.
+VARIABLES: Expanding 'python -c "print \'3.14159265359 ABCD\'"' to 'python -c "print \'3.14159265359 ABCD\'"'
+VARIABLES: Expanding 'python -c "print \'<!(python -c "<(pi)") ABCD\'"' to 'python -c "print \'3.14159265359 ABCD\'"'
+VARIABLES: Executing command 'python -c "print '3.14159265359 ABCD'"' in directory 'None'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<!(python -c "print \'<!(python -c "<(pi)") <(letters_list)\'")' to '3.14159265359 ABCD'
+VARIABLES: Matches: {'content': 'check_str_int', 'is_array': '', 'type': '<', 'replace': '<(check_str_int)'}
+VARIABLES: Expanding 'check_str_int' to 'check_str_int'
+VARIABLES: Found output '6', recursing.
+VARIABLES: Expanding '6' to 6
+VARIABLES: Expanding '<(check_str_int)' to 6
+VARIABLES: Matches: {'content': 'check_int', 'is_array': '', 'type': '<', 'replace': '<(check_int)'}
+VARIABLES: Expanding 'check_int' to 'check_int'
+VARIABLES: Found output '5blah', recursing.
+VARIABLES: Expanding '5blah' to '5blah'
+VARIABLES: Expanding '<(check_int)blah' to '5blah'
+VARIABLES: Matches: {'content': 'not_int_4', 'is_array': '', 'type': '<', 'replace': '<(not_int_4)'}
+VARIABLES: Expanding 'not_int_4' to 'not_int_4'
+VARIABLES: Found output '13.0', recursing.
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding '<(not_int_4)' to '13.0'
+VARIABLES: Matches: {'content': 'not_int_3', 'is_array': '', 'type': '<', 'replace': '<(not_int_3)'}
+VARIABLES: Expanding 'not_int_3' to 'not_int_3'
+VARIABLES: Found output '012', recursing.
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Expanding '<(not_int_3)' to '012'
+VARIABLES: Matches: {'content': 'negative_int', 'is_array': '', 'type': '<', 'replace': '<(negative_int)'}
+VARIABLES: Expanding 'negative_int' to 'negative_int'
+VARIABLES: Found output '-15', recursing.
+VARIABLES: Expanding '-15' to -15
+VARIABLES: Expanding '<(negative_int)' to -15
+VARIABLES: Matches: {'content': 'not_int_5', 'is_array': '', 'type': '<', 'replace': '<(not_int_5)'}
+VARIABLES: Expanding 'not_int_5' to 'not_int_5'
+VARIABLES: Found output '+14', recursing.
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '<(not_int_5)' to '+14'
+VARIABLES: Matches: {'content': 'check_list_int', 'is_array': '', 'type': '<', 'replace': '<(check_list_int)'}
+VARIABLES: Expanding 'check_list_int' to 'check_list_int'
+VARIABLES: Found output '7 8 9', recursing.
+VARIABLES: Expanding '7 8 9' to '7 8 9'
+VARIABLES: Expanding '<(check_list_int)' to '7 8 9'
+VARIABLES: Matches: {'content': 'not_int_2', 'is_array': '', 'type': '<', 'replace': '<(not_int_2)'}
+VARIABLES: Expanding 'not_int_2' to 'not_int_2'
+VARIABLES: Found output '11 ', recursing.
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding '<(not_int_2)' to '11 '
+VARIABLES: Matches: {'content': 'not_int_1', 'is_array': '', 'type': '<', 'replace': '<(not_int_1)'}
+VARIABLES: Expanding 'not_int_1' to 'not_int_1'
+VARIABLES: Found output ' 10', recursing.
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Expanding '<(not_int_1)' to ' 10'
+VARIABLES: Matches: {'content': 'zero_int', 'is_array': '', 'type': '<', 'replace': '<(zero_int)'}
+VARIABLES: Expanding 'zero_int' to 'zero_int'
+VARIABLES: Found output '0', recursing.
+VARIABLES: Expanding '0' to 0
+VARIABLES: Expanding '<(zero_int)' to 0
+VARIABLES: Matches: {'content': 'check_list_int', 'is_array': '', 'type': '<@', 'replace': '<@(check_list_int)'}
+VARIABLES: Expanding 'check_list_int' to 'check_list_int'
+VARIABLES: Found output [7, 8, 9], recursing.
+VARIABLES: Expanding 7 to 7
+VARIABLES: Expanding 8 to 8
+VARIABLES: Expanding 9 to 9
+VARIABLES: Expanding '<@(check_list_int)' to [7, 8, 9]
+VARIABLES: Expanding 'foo' to 'foo'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Matches: {'content': 'var6', 'is_array': '', 'type': '<', 'replace': '<(var6)'}
+VARIABLES: Expanding 'var6' to 'var6'
+VARIABLES: Matches: {'content': 'echo <(var5', 'is_array': '', 'type': '<!', 'replace': '<!(echo <(var5)'}
+VARIABLES: Matches: {'content': 'var5', 'is_array': '', 'type': '<', 'replace': '<(var5)'}
+VARIABLES: Expanding 'var5' to 'var5'
+VARIABLES: Found output 'echo letters_list', recursing.
+VARIABLES: Expanding 'echo letters_list' to 'echo letters_list'
+VARIABLES: Expanding 'echo <(var5)list' to 'echo letters_list'
+VARIABLES: Executing command 'echo letters_list' in directory 'None'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<!(echo <(var5)<(var6))' to 'letters_list'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Matches: {'content': '_inputs', 'is_array': '', 'type': '<', 'replace': '<(_inputs)'}
+VARIABLES: Expanding '_inputs' to '_inputs'
+VARIABLES: Matches: {'content': 'var2', 'is_array': '', 'type': '<', 'replace': '<(var2)'}
+VARIABLES: Expanding 'var2' to 'var2'
+VARIABLES: Found output '3.14159265359 ABCD', recursing.
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '<(var2)' to '3.14159265359 ABCD'
+VARIABLES: Found output '"3.14159265359 ABCD"', recursing.
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding '<(_inputs)' to '"3.14159265359 ABCD"'
+VARIABLES: Matches: {'content': '_outputs', 'is_array': '', 'type': '<', 'replace': '<(_outputs)'}
+VARIABLES: Expanding '_outputs' to '_outputs'
+VARIABLES: Matches: {'content': 'var4', 'is_array': '', 'type': '<', 'replace': '<(var4)'}
+VARIABLES: Expanding 'var4' to 'var4'
+VARIABLES: Found output 'ABCD', recursing.
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '<(var4)' to 'ABCD'
+VARIABLES: Matches: {'content': 'var7', 'is_array': '', 'type': '<', 'replace': '<(var7)'}
+VARIABLES: Expanding 'var7' to 'var7'
+VARIABLES: Found output 'letters_list', recursing.
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding '<(var7)' to 'letters_list'
+VARIABLES: Found output 'ABCD letters_list', recursing.
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '<(_outputs)' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'dummy' to 'dummy'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'commands.gyp' to 'commands.gyp'
+VARIABLES: Expanding 'commands.gypi' to 'commands.gypi'
+VARIABLES: Expanding 'dummy' to 'dummy'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'letters_' to 'letters_'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'list' to 'list'
+VARIABLES: Expanding '3.14159265359' to '3.14159265359'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding '5blah' to '5blah'
+VARIABLES: Expanding '13.0' to '13.0'
+VARIABLES: Expanding '012' to '012'
+VARIABLES: Expanding '+14' to '+14'
+VARIABLES: Expanding '7 8 9' to '7 8 9'
+VARIABLES: Expanding '11 ' to '11 '
+VARIABLES: Expanding ' 10' to ' 10'
+VARIABLES: Expanding 'foo' to 'foo'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'echo' to 'echo'
+VARIABLES: Expanding '"3.14159265359 ABCD"' to '"3.14159265359 ABCD"'
+VARIABLES: Expanding 'ABCD letters_list' to 'ABCD letters_list'
+VARIABLES: Expanding '3.14159265359 ABCD' to '3.14159265359 ABCD'
+VARIABLES: Expanding 'ABCD' to 'ABCD'
+VARIABLES: Expanding 'letters_list' to 'letters_list'
diff --git a/Source/ThirdParty/gyp/test/variables/commands/commands.gypd.golden b/Source/ThirdParty/gyp/test/variables/commands/commands.gypd.golden
new file mode 100644
index 000000000..e9aaf0202
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/commands.gypd.golden
@@ -0,0 +1,54 @@
+{'_DEPTH': '.',
+ 'included_files': ['commands.gyp', 'commands.gypi'],
+ 'targets': [{'actions': [{'action': ['echo',
+ '"3.14159265359 ABCD"',
+ 'ABCD letters_list'],
+ 'action_name': 'test_action',
+ 'inputs': ['3.14159265359 ABCD'],
+ 'outputs': ['ABCD', 'letters_list'],
+ 'variables': {'var7': 'letters_list'}}],
+ 'configurations': {'Default': {}},
+ 'default_configuration': 'Default',
+ 'target_name': 'foo',
+ 'toolset': 'target',
+ 'type': 'none',
+ 'variables': {'var1': '3.14159265359',
+ 'var10': '7 8 9',
+ 'var11': ['7', '8', '9'],
+ 'var12': ' 10',
+ 'var13': '11 ',
+ 'var14': '012',
+ 'var15': '13.0',
+ 'var16': '+14',
+ 'var17': '-15',
+ 'var18': '0',
+ 'var2': '3.14159265359 ABCD',
+ 'var3': 'ABCD',
+ 'var4': 'ABCD',
+ 'var5': 'letters_',
+ 'var6': 'list',
+ 'var7': '5',
+ 'var8': '5blah',
+ 'var9': '6'}},
+ {'configurations': {'Default': {}},
+ 'default_configuration': 'Default',
+ 'target_name': 'dummy',
+ 'toolset': 'target',
+ 'type': 'none'}],
+ 'variables': {'check_included': 'XYZ',
+ 'check_int': '5',
+ 'check_list_int': ['7', '8', '9'],
+ 'check_lists': ['XYZ', 'ABCDEFGHIJK'],
+ 'check_str_int': '6',
+ 'included_variable': 'XYZ',
+ 'letters_list': 'ABCD',
+ 'negative_int': '-15',
+ 'not_int_1': ' 10',
+ 'not_int_2': '11 ',
+ 'not_int_3': '012',
+ 'not_int_4': '13.0',
+ 'not_int_5': '+14',
+ 'other_letters': 'ABCDEFG',
+ 'pi': 'import math; print math.pi',
+ 'third_letters': 'ABCDEFGHIJK',
+ 'zero_int': '0'}}
diff --git a/Source/ThirdParty/gyp/test/variables/commands/commands.gypi b/Source/ThirdParty/gyp/test/variables/commands/commands.gypi
new file mode 100644
index 000000000..6b2249715
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/commands.gypi
@@ -0,0 +1,16 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file is included from commands.gyp to test evaluation order of includes.
+{
+ 'variables': {
+ 'included_variable': 'XYZ',
+ },
+ 'targets': [
+ {
+ 'target_name': 'dummy',
+ 'type': 'none',
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands-ignore-env.py b/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands-ignore-env.py
new file mode 100644
index 000000000..33ce1b58f
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands-ignore-env.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test that environment variables are ignored when --ignore-environment is
+specified.
+"""
+
+import os
+
+import TestGyp
+
+os.environ['GYP_DEFINES'] = 'FOO=BAR'
+os.environ['GYP_GENERATORS'] = 'foo'
+os.environ['GYP_GENERATOR_FLAGS'] = 'genflag=foo'
+os.environ['GYP_GENERATOR_OUTPUT'] = 'somedir'
+
+test = TestGyp.TestGyp(format='gypd')
+
+expect = test.read('commands.gyp.ignore-env.stdout').replace('\r', '')
+
+# Set $HOME so that gyp doesn't read the user's actual
+# ~/.gyp/include.gypi file, which may contain variables
+# and other settings that would change the output.
+os.environ['HOME'] = test.workpath()
+
+test.run_gyp('commands.gyp',
+ '--debug', 'variables', '--debug', 'general',
+ '--ignore-environment',
+ stdout=expect)
+
+# Verify the commands.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system. Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('commands.gypd').replace('\r', '')
+expect = test.read('commands.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+ print "Unexpected contents of `commands.gypd'"
+ test.diff(expect, contents, 'commands.gypd ')
+ test.fail_test()
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands-repeated.py b/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands-repeated.py
new file mode 100644
index 000000000..3009afeaa
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands-repeated.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test variable expansion of '<!()' syntax commands where they are evaluated
+more then once..
+"""
+
+import os
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+expect = test.read('commands-repeated.gyp.stdout').replace('\r', '')
+
+# Set $HOME so that gyp doesn't read the user's actual
+# ~/.gyp/include.gypi file, which may contain variables
+# and other settings that would change the output.
+os.environ['HOME'] = test.workpath()
+
+test.run_gyp('commands-repeated.gyp',
+ '--debug', 'variables', '--debug', 'general',
+ stdout=expect)
+
+# Verify the commands-repeated.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system. Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('commands-repeated.gypd').replace('\r', '')
+expect = test.read('commands-repeated.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+ print "Unexpected contents of `commands-repeated.gypd'"
+ test.diff(expect, contents, 'commands-repeated.gypd ')
+ test.fail_test()
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands.py b/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands.py
new file mode 100644
index 000000000..0dc154766
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/gyptest-commands.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test variable expansion of '<!()' syntax commands.
+"""
+
+import os
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+expect = test.read('commands.gyp.stdout').replace('\r', '')
+
+# Set $HOME so that gyp doesn't read the user's actual
+# ~/.gyp/include.gypi file, which may contain variables
+# and other settings that would change the output.
+os.environ['HOME'] = test.workpath()
+
+test.run_gyp('commands.gyp',
+ '--debug', 'variables', '--debug', 'general',
+ stdout=expect)
+
+# Verify the commands.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system. Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('commands.gypd').replace('\r', '')
+expect = test.read('commands.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+ print "Unexpected contents of `commands.gypd'"
+ test.diff(expect, contents, 'commands.gypd ')
+ test.fail_test()
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/variables/commands/update_golden b/Source/ThirdParty/gyp/test/variables/commands/update_golden
new file mode 100755
index 000000000..e8da558a2
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/commands/update_golden
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+python ../../../gyp --debug variables --debug general --format gypd --depth . commands.gyp > commands.gyp.stdout
+python ../../../gyp --ignore-environment --debug variables --debug general --format gypd --depth . commands.gyp > commands.gyp.ignore-env.stdout
+cp -f commands.gypd commands.gypd.golden
+python ../../../gyp --debug variables --debug general --format gypd --depth . commands-repeated.gyp > commands-repeated.gyp.stdout
+cp -f commands-repeated.gypd commands-repeated.gypd.golden
diff --git a/Source/ThirdParty/gyp/test/variables/filelist/filelist.gyp.stdout b/Source/ThirdParty/gyp/test/variables/filelist/filelist.gyp.stdout
new file mode 100644
index 000000000..f541267a9
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/filelist/filelist.gyp.stdout
@@ -0,0 +1,174 @@
+GENERAL: running with these options:
+GENERAL: check: None
+GENERAL: circular_check: True
+GENERAL: debug: ['variables', 'general']
+GENERAL: defines: None
+GENERAL: depth: '.'
+GENERAL: formats: ['gypd']
+GENERAL: generator_flags: []
+GENERAL: generator_output: None
+GENERAL: includes: None
+GENERAL: msvs_version: None
+GENERAL: suffix: ''
+GENERAL: toplevel_dir: None
+GENERAL: use_environment: True
+GENERAL: cmdline_default_variables: {}
+GENERAL: generator_flags: {}
+VARIABLES: Expanding 'exclude' to 'exclude'
+VARIABLES: Expanding 'Sch.*' to 'Sch.*'
+VARIABLES: Expanding 'include' to 'include'
+VARIABLES: Expanding '.*dt' to '.*dt'
+VARIABLES: Expanding 'exclude' to 'exclude'
+VARIABLES: Expanding 'Jer.*' to 'Jer.*'
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Astor' to 'Astor'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Jerome' to 'Jerome'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Expanding 'Schultz' to 'Schultz'
+VARIABLES: Expanding 'Astor' to 'Astor'
+VARIABLES: Expanding '.' to '.'
+VARIABLES: Matches: {'content': 'names.txt <@(names', 'is_array': '', 'type': '<|', 'replace': '<|(names.txt <@(names)'}
+VARIABLES: Matches: {'content': 'names', 'is_array': '', 'type': '<@', 'replace': '<@(names)'}
+VARIABLES: Expanding 'names' to 'names'
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Found output 'names.txt John Jacob Jingleheimer Schmidt', recursing.
+VARIABLES: Expanding 'names.txt John Jacob Jingleheimer Schmidt' to 'names.txt John Jacob Jingleheimer Schmidt'
+VARIABLES: Expanding 'names.txt <@(names)' to 'names.txt John Jacob Jingleheimer Schmidt'
+VARIABLES: Found output 'names.txt', recursing.
+VARIABLES: Expanding 'names.txt' to 'names.txt'
+VARIABLES: Expanding '<|(names.txt <@(names))' to 'names.txt'
+VARIABLES: Expanding 'foo' to 'foo'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'python' to 'python'
+VARIABLES: Expanding 'dummy.py' to 'dummy.py'
+VARIABLES: Matches: {'content': 'names_listfile', 'is_array': '', 'type': '<', 'replace': '<(names_listfile)'}
+VARIABLES: Expanding 'names_listfile' to 'names_listfile'
+VARIABLES: Found output 'names.txt', recursing.
+VARIABLES: Expanding 'names.txt' to 'names.txt'
+VARIABLES: Expanding '<(names_listfile)' to 'names.txt'
+VARIABLES: Matches: {'content': 'names_listfile', 'is_array': '', 'type': '<', 'replace': '<(names_listfile)'}
+VARIABLES: Expanding 'names_listfile' to 'names_listfile'
+VARIABLES: Found output 'names.txt', recursing.
+VARIABLES: Expanding 'names.txt' to 'names.txt'
+VARIABLES: Expanding '<(names_listfile)' to 'names.txt'
+VARIABLES: Matches: {'content': 'cat <(names_listfile', 'is_array': '', 'type': '<!@', 'replace': '<!@(cat <(names_listfile)'}
+VARIABLES: Matches: {'content': 'names_listfile', 'is_array': '', 'type': '<', 'replace': '<(names_listfile)'}
+VARIABLES: Expanding 'names_listfile' to 'names_listfile'
+VARIABLES: Found output 'cat names.txt', recursing.
+VARIABLES: Expanding 'cat names.txt' to 'cat names.txt'
+VARIABLES: Expanding 'cat <(names_listfile)' to 'cat names.txt'
+VARIABLES: Executing command 'cat names.txt' in directory 'src'
+VARIABLES: Found output ['John', 'Jacob', 'Jingleheimer', 'Schmidt'], recursing.
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Expanding '<!@(cat <(names_listfile))' to ['John', 'Jacob', 'Jingleheimer', 'Schmidt']
+VARIABLES: Expanding 'dummy_foo' to 'dummy_foo'
+VARIABLES: Matches: {'content': 'sources.txt <@(_sources', 'is_array': '', 'type': '<|', 'replace': '<|(sources.txt <@(_sources)'}
+VARIABLES: Matches: {'content': '_sources', 'is_array': '', 'type': '<@', 'replace': '<@(_sources)'}
+VARIABLES: Expanding '_sources' to '_sources'
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Found output 'sources.txt John Jacob Jingleheimer Schmidt', recursing.
+VARIABLES: Expanding 'sources.txt John Jacob Jingleheimer Schmidt' to 'sources.txt John Jacob Jingleheimer Schmidt'
+VARIABLES: Expanding 'sources.txt <@(_sources)' to 'sources.txt John Jacob Jingleheimer Schmidt'
+VARIABLES: Found output 'sources.txt', recursing.
+VARIABLES: Expanding 'sources.txt' to 'sources.txt'
+VARIABLES: Expanding '<|(sources.txt <@(_sources))' to 'sources.txt'
+VARIABLES: Expanding 'bar' to 'bar'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'exclude' to 'exclude'
+VARIABLES: Expanding 'Sch.*' to 'Sch.*'
+VARIABLES: Expanding 'include' to 'include'
+VARIABLES: Expanding '.*dt' to '.*dt'
+VARIABLES: Expanding 'exclude' to 'exclude'
+VARIABLES: Expanding 'Jer.*' to 'Jer.*'
+VARIABLES: Expanding 'Astor' to 'Astor'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'python' to 'python'
+VARIABLES: Expanding 'dummy.py' to 'dummy.py'
+VARIABLES: Matches: {'content': 'sources_listfile', 'is_array': '', 'type': '<', 'replace': '<(sources_listfile)'}
+VARIABLES: Expanding 'sources_listfile' to 'sources_listfile'
+VARIABLES: Found output 'sources.txt', recursing.
+VARIABLES: Expanding 'sources.txt' to 'sources.txt'
+VARIABLES: Expanding '<(sources_listfile)' to 'sources.txt'
+VARIABLES: Matches: {'content': 'sources_listfile', 'is_array': '', 'type': '<', 'replace': '<(sources_listfile)'}
+VARIABLES: Expanding 'sources_listfile' to 'sources_listfile'
+VARIABLES: Found output 'sources.txt', recursing.
+VARIABLES: Expanding 'sources.txt' to 'sources.txt'
+VARIABLES: Expanding '<(sources_listfile)' to 'sources.txt'
+VARIABLES: Matches: {'content': 'cat <(sources_listfile', 'is_array': '', 'type': '<!@', 'replace': '<!@(cat <(sources_listfile)'}
+VARIABLES: Matches: {'content': 'sources_listfile', 'is_array': '', 'type': '<', 'replace': '<(sources_listfile)'}
+VARIABLES: Expanding 'sources_listfile' to 'sources_listfile'
+VARIABLES: Found output 'cat sources.txt', recursing.
+VARIABLES: Expanding 'cat sources.txt' to 'cat sources.txt'
+VARIABLES: Expanding 'cat <(sources_listfile)' to 'cat sources.txt'
+VARIABLES: Executing command 'cat sources.txt' in directory 'src'
+VARIABLES: Found output ['John', 'Jacob', 'Jingleheimer', 'Schmidt'], recursing.
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Expanding '<!@(cat <(sources_listfile))' to ['John', 'Jacob', 'Jingleheimer', 'Schmidt']
+VARIABLES: Expanding 'dummy_foo' to 'dummy_foo'
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Astor' to 'Astor'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Jerome' to 'Jerome'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Expanding 'Schultz' to 'Schultz'
+VARIABLES: Expanding 'filelist.gyp' to 'filelist.gyp'
+VARIABLES: Expanding 'names.txt' to 'names.txt'
+VARIABLES: Expanding 'foo' to 'foo'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'python' to 'python'
+VARIABLES: Expanding 'dummy.py' to 'dummy.py'
+VARIABLES: Expanding 'names.txt' to 'names.txt'
+VARIABLES: Expanding 'names.txt' to 'names.txt'
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Expanding 'dummy_foo' to 'dummy_foo'
+VARIABLES: Expanding 'sources.txt' to 'sources.txt'
+VARIABLES: Expanding 'bar' to 'bar'
+VARIABLES: Expanding 'target' to 'target'
+VARIABLES: Expanding 'none' to 'none'
+VARIABLES: Expanding 'exclude' to 'exclude'
+VARIABLES: Expanding 'Sch.*' to 'Sch.*'
+VARIABLES: Expanding 'include' to 'include'
+VARIABLES: Expanding '.*dt' to '.*dt'
+VARIABLES: Expanding 'exclude' to 'exclude'
+VARIABLES: Expanding 'Jer.*' to 'Jer.*'
+VARIABLES: Expanding 'Astor' to 'Astor'
+VARIABLES: Expanding 'test_action' to 'test_action'
+VARIABLES: Expanding 'python' to 'python'
+VARIABLES: Expanding 'dummy.py' to 'dummy.py'
+VARIABLES: Expanding 'sources.txt' to 'sources.txt'
+VARIABLES: Expanding 'sources.txt' to 'sources.txt'
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Expanding 'dummy_foo' to 'dummy_foo'
+VARIABLES: Expanding 'John' to 'John'
+VARIABLES: Expanding 'Jacob' to 'Jacob'
+VARIABLES: Expanding 'Astor' to 'Astor'
+VARIABLES: Expanding 'Jingleheimer' to 'Jingleheimer'
+VARIABLES: Expanding 'Jerome' to 'Jerome'
+VARIABLES: Expanding 'Schmidt' to 'Schmidt'
+VARIABLES: Expanding 'Schultz' to 'Schultz'
diff --git a/Source/ThirdParty/gyp/test/variables/filelist/filelist.gypd.golden b/Source/ThirdParty/gyp/test/variables/filelist/filelist.gypd.golden
new file mode 100644
index 000000000..09d911604
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/filelist/filelist.gypd.golden
@@ -0,0 +1,43 @@
+{'_DEPTH': '.',
+ 'included_files': ['filelist.gyp'],
+ 'targets': [{'actions': [{'action': ['python', 'dummy.py', 'names.txt'],
+ 'action_name': 'test_action',
+ 'inputs': ['names.txt',
+ 'John',
+ 'Jacob',
+ 'Jingleheimer',
+ 'Schmidt'],
+ 'outputs': ['dummy_foo']}],
+ 'configurations': {'Default': {}},
+ 'default_configuration': 'Default',
+ 'target_name': 'foo',
+ 'toolset': 'target',
+ 'type': 'none',
+ 'variables': {'names_listfile': 'names.txt'}},
+ {'actions': [{'action': ['python', 'dummy.py', 'sources.txt'],
+ 'action_name': 'test_action',
+ 'inputs': ['sources.txt',
+ 'John',
+ 'Jacob',
+ 'Jingleheimer',
+ 'Schmidt'],
+ 'outputs': ['dummy_foo']}],
+ 'configurations': {'Default': {}},
+ 'default_configuration': 'Default',
+ 'sources': ['John', 'Jacob', 'Jingleheimer', 'Schmidt'],
+ 'sources_excluded': ['Astor', 'Jerome', 'Schultz'],
+ 'target_name': 'bar',
+ 'toolset': 'target',
+ 'type': 'none',
+ 'variables': {'sources_listfile': 'sources.txt'}}],
+ 'variables': {'names': ['John',
+ 'Jacob',
+ 'Astor',
+ 'Jingleheimer',
+ 'Jerome',
+ 'Schmidt',
+ 'Schultz'],
+ 'names!': ['Astor'],
+ 'names/': [['exclude', 'Sch.*'],
+ ['include', '.*dt'],
+ ['exclude', 'Jer.*']]}}
diff --git a/Source/ThirdParty/gyp/test/variables/filelist/gyptest-filelist.py b/Source/ThirdParty/gyp/test/variables/filelist/gyptest-filelist.py
new file mode 100644
index 000000000..4fb0d9a93
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/filelist/gyptest-filelist.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Test variable expansion of '<|(list.txt ...)' syntax commands.
+"""
+
+import os
+import sys
+
+import TestGyp
+
+test = TestGyp.TestGyp(format='gypd')
+
+expect = test.read('filelist.gyp.stdout')
+if sys.platform == 'win32':
+ expect = expect.replace('/', r'\\').replace('\r', '')
+
+# Set $HOME so that gyp doesn't read the user's actual
+# ~/.gyp/include.gypi file, which may contain variables
+# and other settings that would change the output.
+os.environ['HOME'] = test.workpath()
+
+test.run_gyp('src/filelist.gyp',
+ '--debug', 'variables', '--debug', 'general',
+ stdout=expect)
+
+# Verify the filelist.gypd against the checked-in expected contents.
+#
+# Normally, we should canonicalize line endings in the expected
+# contents file setting the Subversion svn:eol-style to native,
+# but that would still fail if multiple systems are sharing a single
+# workspace on a network-mounted file system. Consequently, we
+# massage the Windows line endings ('\r\n') in the output to the
+# checked-in UNIX endings ('\n').
+
+contents = test.read('src/filelist.gypd').replace(
+ '\r', '').replace('\\\\', '/')
+expect = test.read('filelist.gypd.golden').replace('\r', '')
+if not test.match(contents, expect):
+ print "Unexpected contents of `src/filelist.gypd'"
+ test.diff(expect, contents, 'src/filelist.gypd ')
+ test.fail_test()
+
+contents = test.read('src/names.txt')
+expect = 'John\nJacob\nJingleheimer\nSchmidt\n'
+if not test.match(contents, expect):
+ print "Unexpected contents of `src/names.txt'"
+ test.diff(expect, contents, 'src/names.txt ')
+ test.fail_test()
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/variables/filelist/src/filelist.gyp b/Source/ThirdParty/gyp/test/variables/filelist/src/filelist.gyp
new file mode 100644
index 000000000..df48eb3e4
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/filelist/src/filelist.gyp
@@ -0,0 +1,93 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This is a test to make sure that <|(foo.txt a b c) generates
+# a pre-calculated file list at gyp time and returns foo.txt.
+# This feature is useful to work around limits in the number of arguments that
+# can be passed to rule/action.
+
+{
+ 'variables': {
+ 'names': [
+ 'John',
+ 'Jacob',
+ 'Astor',
+ 'Jingleheimer',
+ 'Jerome',
+ 'Schmidt',
+ 'Schultz',
+ ],
+ 'names!': [
+ 'Astor',
+ ],
+ 'names/': [
+ ['exclude', 'Sch.*'],
+ ['include', '.*dt'],
+ ['exclude', 'Jer.*'],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'foo',
+ 'type': 'none',
+ 'variables': {
+ 'names_listfile': '<|(names.txt <@(names))',
+ },
+ 'actions': [
+ {
+ 'action_name': 'test_action',
+ 'inputs' : [
+ '<(names_listfile)',
+ '<!@(cat <(names_listfile))',
+ ],
+ 'outputs': [
+ 'dummy_foo',
+ ],
+ 'action': [
+ 'python', 'dummy.py', '<(names_listfile)',
+ ],
+ },
+ ],
+ },
+ {
+ 'target_name': 'bar',
+ 'type': 'none',
+ 'sources': [
+ 'John',
+ 'Jacob',
+ 'Astor',
+ 'Jingleheimer',
+ 'Jerome',
+ 'Schmidt',
+ 'Schultz',
+ ],
+ 'sources!': [
+ 'Astor',
+ ],
+ 'sources/': [
+ ['exclude', 'Sch.*'],
+ ['include', '.*dt'],
+ ['exclude', 'Jer.*'],
+ ],
+ 'variables': {
+ 'sources_listfile': '<|(sources.txt <@(_sources))',
+ },
+ 'actions': [
+ {
+ 'action_name': 'test_action',
+ 'inputs' : [
+ '<(sources_listfile)',
+ '<!@(cat <(sources_listfile))',
+ ],
+ 'outputs': [
+ 'dummy_foo',
+ ],
+ 'action': [
+ 'python', 'dummy.py', '<(sources_listfile)',
+ ],
+ },
+ ],
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/test/variables/filelist/update_golden b/Source/ThirdParty/gyp/test/variables/filelist/update_golden
new file mode 100755
index 000000000..b4d489a34
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variables/filelist/update_golden
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+python ../../../gyp --debug variables --debug general --format gypd --depth . src/filelist.gyp > filelist.gyp.stdout
+cp -f src/filelist.gypd filelist.gypd.golden
diff --git a/Source/ThirdParty/gyp/test/variants/gyptest-variants.py b/Source/ThirdParty/gyp/test/variants/gyptest-variants.py
new file mode 100644
index 000000000..ce2455f66
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variants/gyptest-variants.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verify handling of build variants.
+
+TODO: Right now, only the SCons generator supports this, so the
+test case is SCons-specific. In particular, it relise on SCons'
+ability to rebuild in response to changes on the command line. It
+may be simpler to just drop this feature if the other generators
+can't be made to behave the same way.
+"""
+
+import TestGyp
+
+test = TestGyp.TestGyp(formats=['scons'])
+
+test.run_gyp('variants.gyp', chdir='src')
+
+test.relocate('src', 'relocate/src')
+
+test.build('variants.gyp', chdir='relocate/src')
+
+test.run_built_executable('variants',
+ chdir='relocate/src',
+ stdout="Hello, world!\n")
+
+test.sleep()
+test.build('variants.gyp', 'VARIANT1=1', chdir='relocate/src')
+
+test.run_built_executable('variants',
+ chdir='relocate/src',
+ stdout="Hello from VARIANT1\n")
+
+test.sleep()
+test.build('variants.gyp', 'VARIANT2=1', chdir='relocate/src')
+
+test.run_built_executable('variants',
+ chdir='relocate/src',
+ stdout="Hello from VARIANT2\n")
+
+test.pass_test()
diff --git a/Source/ThirdParty/gyp/test/variants/src/variants.c b/Source/ThirdParty/gyp/test/variants/src/variants.c
new file mode 100644
index 000000000..3018e40df
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variants/src/variants.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+#if defined(VARIANT1)
+ printf("Hello from VARIANT1\n");
+#elif defined(VARIANT2)
+ printf("Hello from VARIANT2\n");
+#else
+ printf("Hello, world!\n");
+#endif
+ return 0;
+}
diff --git a/Source/ThirdParty/gyp/test/variants/src/variants.gyp b/Source/ThirdParty/gyp/test/variants/src/variants.gyp
new file mode 100644
index 000000000..0305ca747
--- /dev/null
+++ b/Source/ThirdParty/gyp/test/variants/src/variants.gyp
@@ -0,0 +1,27 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'variants',
+ 'type': 'executable',
+ 'sources': [
+ 'variants.c',
+ ],
+ 'variants': {
+ 'variant1' : {
+ 'defines': [
+ 'VARIANT1',
+ ],
+ },
+ 'variant2' : {
+ 'defines': [
+ 'VARIANT2',
+ ],
+ },
+ },
+ },
+ ],
+}
diff --git a/Source/ThirdParty/gyp/tools/README b/Source/ThirdParty/gyp/tools/README
new file mode 100644
index 000000000..712e4efbb
--- /dev/null
+++ b/Source/ThirdParty/gyp/tools/README
@@ -0,0 +1,15 @@
+pretty_vcproj:
+ Usage: pretty_vcproj.py "c:\path\to\vcproj.vcproj" [key1=value1] [key2=value2]
+
+ They key/value pair are used to resolve vsprops name.
+
+ For example, if I want to diff the base.vcproj project:
+
+ pretty_vcproj.py z:\dev\src-chrome\src\base\build\base.vcproj "$(SolutionDir)=z:\dev\src-chrome\src\chrome\\" "$(CHROMIUM_BUILD)=" "$(CHROME_BUILD_TYPE)=" > orignal.txt
+ pretty_vcproj.py z:\dev\src-chrome\src\base\base_gyp.vcproj "$(SolutionDir)=z:\dev\src-chrome\src\chrome\\" "$(CHROMIUM_BUILD)=" "$(CHROME_BUILD_TYPE)=" > gyp.txt
+
+ And you can use your favorite diff tool to see the changes.
+
+ Note: In the case of base.vcproj, the original vcproj is one level up the generated one.
+ I suggest you do a search and replace for '"..\' and replace it with '"' in original.txt
+ before you perform the diff. \ No newline at end of file
diff --git a/Source/ThirdParty/gyp/tools/pretty_gyp.py b/Source/ThirdParty/gyp/tools/pretty_gyp.py
new file mode 100644
index 000000000..04c79012e
--- /dev/null
+++ b/Source/ThirdParty/gyp/tools/pretty_gyp.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This file pretty-prints the contents of a GYP file.
+
+import sys
+import re
+
+input = []
+if len(sys.argv) > 1:
+ input_file = open(sys.argv[1])
+ input = input_file.read().splitlines()
+ input_file.close()
+else:
+ input = sys.stdin.read().splitlines()
+
+# This is used to remove comments when we're counting braces.
+comment_re = re.compile(r'\s*#.*')
+
+# This is used to remove quoted strings when we're counting braces.
+# It takes into account quoted quotes, and makes sure that the quotes
+# match.
+# NOTE: It does not handle quotes that span more than one line, or
+# cases where an escaped quote is preceeded by an escaped backslash.
+quote_re_str = r'(?P<q>[\'"])(.*?)(?<![^\\][\\])(?P=q)'
+quote_re = re.compile(quote_re_str)
+
+def comment_replace(matchobj):
+ return matchobj.group(1) + matchobj.group(2) + '#' * len(matchobj.group(3))
+
+def mask_comments(input):
+ # This is used to mask the quoted strings so we skip braces inside
+ # quoted strings.
+ search_re = re.compile(r'(.*?)(#)(.*)')
+ return [search_re.sub(comment_replace, line) for line in input]
+
+def quote_replace(matchobj):
+ return "%s%s%s%s" % (matchobj.group(1),
+ matchobj.group(2),
+ 'x'*len(matchobj.group(3)),
+ matchobj.group(2))
+
+def mask_quotes(input):
+ # This is used to mask the quoted strings so we skip braces inside
+ # quoted strings.
+ search_re = re.compile(r'(.*?)' + quote_re_str)
+ return [search_re.sub(quote_replace, line) for line in input]
+
+def do_split(input, masked_input, search_re):
+ output = []
+ mask_output = []
+ for (line, masked_line) in zip(input, masked_input):
+ m = search_re.match(masked_line)
+ while m:
+ split = len(m.group(1))
+ line = line[:split] + r'\n' + line[split:]
+ masked_line = masked_line[:split] + r'\n' + masked_line[split:]
+ m = search_re.match(masked_line)
+ output.extend(line.split(r'\n'))
+ mask_output.extend(masked_line.split(r'\n'))
+ return (output, mask_output)
+
+# This masks out the quotes and comments, and then splits appropriate
+# lines (lines that matche the double_*_brace re's above) before
+# indenting them below.
+def split_double_braces(input):
+ # These are used to split lines which have multiple braces on them, so
+ # that the indentation looks prettier when all laid out (e.g. closing
+ # braces make a nice diagonal line).
+ double_open_brace_re = re.compile(r'(.*?[\[\{\(,])(\s*)([\[\{\(])')
+ double_close_brace_re = re.compile(r'(.*?[\]\}\)],?)(\s*)([\]\}\)])')
+
+ masked_input = mask_quotes(input)
+ masked_input = mask_comments(masked_input)
+
+ (output, mask_output) = do_split(input, masked_input, double_open_brace_re)
+ (output, mask_output) = do_split(output, mask_output, double_close_brace_re)
+
+ return output
+
+# This keeps track of the number of braces on a given line and returns
+# the result. It starts at zero and subtracts for closed braces, and
+# adds for open braces.
+def count_braces(line):
+ open_braces = ['[', '(', '{']
+ close_braces = [']', ')', '}']
+ closing_prefix_re = re.compile(r'(.*?[^\s\]\}\)]+.*?)([\]\}\)],?)\s*$')
+ cnt = 0
+ stripline = comment_re.sub(r'', line)
+ stripline = quote_re.sub(r"''", stripline)
+ for char in stripline:
+ for brace in open_braces:
+ if char == brace:
+ cnt += 1
+ for brace in close_braces:
+ if char == brace:
+ cnt -= 1
+
+ after = False
+ if cnt > 0:
+ after = True
+
+ # This catches the special case of a closing brace having something
+ # other than just whitespace ahead of it -- we don't want to
+ # unindent that until after this line is printed so it stays with
+ # the previous indentation level.
+ if cnt < 0 and closing_prefix_re.match(stripline):
+ after = True
+ return (cnt, after)
+
+# This does the main work of indenting the input based on the brace counts.
+def prettyprint_input(lines):
+ indent = 0
+ basic_offset = 2
+ last_line = ""
+ for line in lines:
+ if comment_re.match(line):
+ print line
+ else:
+ line = line.strip('\r\n\t ') # Otherwise doesn't strip \r on Unix.
+ if len(line) > 0:
+ (brace_diff, after) = count_braces(line)
+ if brace_diff != 0:
+ if after:
+ print " " * (basic_offset * indent) + line
+ indent += brace_diff
+ else:
+ indent += brace_diff
+ print " " * (basic_offset * indent) + line
+ else:
+ print " " * (basic_offset * indent) + line
+ else:
+ print ""
+ last_line = line
+
+# Split up the double braces.
+lines = split_double_braces(input)
+
+# Indent and print the output.
+prettyprint_input(lines)
diff --git a/Source/ThirdParty/gyp/tools/pretty_sln.py b/Source/ThirdParty/gyp/tools/pretty_sln.py
new file mode 100755
index 000000000..0741fff17
--- /dev/null
+++ b/Source/ThirdParty/gyp/tools/pretty_sln.py
@@ -0,0 +1,167 @@
+#!/usr/bin/python2.5
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Prints the information in a sln file in a diffable way.
+
+ It first outputs each projects in alphabetical order with their
+ dependencies.
+
+ Then it outputs a possible build order.
+"""
+
+__author__ = 'nsylvain (Nicolas Sylvain)'
+
+import os
+import re
+import sys
+import pretty_vcproj
+
+def BuildProject(project, built, projects, deps):
+ # if all dependencies are done, we can build it, otherwise we try to build the
+ # dependency.
+ # This is not infinite-recursion proof.
+ for dep in deps[project]:
+ if dep not in built:
+ BuildProject(dep, built, projects, deps)
+ print project
+ built.append(project)
+
+def ParseSolution(solution_file):
+ # All projects, their clsid and paths.
+ projects = dict()
+
+ # A list of dependencies associated with a project.
+ dependencies = dict()
+
+ # Regular expressions that matches the SLN format.
+ # The first line of a project definition.
+ begin_project = re.compile(('^Project\("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942'
+ '}"\) = "(.*)", "(.*)", "(.*)"$'))
+ # The last line of a project definition.
+ end_project = re.compile('^EndProject$')
+ # The first line of a dependency list.
+ begin_dep = re.compile('ProjectSection\(ProjectDependencies\) = postProject$')
+ # The last line of a dependency list.
+ end_dep = re.compile('EndProjectSection$')
+ # A line describing a dependency.
+ dep_line = re.compile(' *({.*}) = ({.*})$')
+
+ in_deps = False
+ solution = open(solution_file)
+ for line in solution:
+ results = begin_project.search(line)
+ if results:
+ # Hack to remove icu because the diff is too different.
+ if results.group(1).find('icu') != -1:
+ continue
+ # We remove "_gyp" from the names because it helps to diff them.
+ current_project = results.group(1).replace('_gyp', '')
+ projects[current_project] = [results.group(2).replace('_gyp', ''),
+ results.group(3),
+ results.group(2)]
+ dependencies[current_project] = []
+ continue
+
+ results = end_project.search(line)
+ if results:
+ current_project = None
+ continue
+
+ results = begin_dep.search(line)
+ if results:
+ in_deps = True
+ continue
+
+ results = end_dep.search(line)
+ if results:
+ in_deps = False
+ continue
+
+ results = dep_line.search(line)
+ if results and in_deps and current_project:
+ dependencies[current_project].append(results.group(1))
+ continue
+
+ # Change all dependencies clsid to name instead.
+ for project in dependencies:
+ # For each dependencies in this project
+ new_dep_array = []
+ for dep in dependencies[project]:
+ # Look for the project name matching this cldis
+ for project_info in projects:
+ if projects[project_info][1] == dep:
+ new_dep_array.append(project_info)
+ dependencies[project] = sorted(new_dep_array)
+
+ return (projects, dependencies)
+
+def PrintDependencies(projects, deps):
+ print "---------------------------------------"
+ print "Dependencies for all projects"
+ print "---------------------------------------"
+ print "-- --"
+
+ for (project, dep_list) in sorted(deps.items()):
+ print "Project : %s" % project
+ print "Path : %s" % projects[project][0]
+ if dep_list:
+ for dep in dep_list:
+ print " - %s" % dep
+ print ""
+
+ print "-- --"
+
+def PrintBuildOrder(projects, deps):
+ print "---------------------------------------"
+ print "Build order "
+ print "---------------------------------------"
+ print "-- --"
+
+ built = []
+ for (project, dep_list) in sorted(deps.items()):
+ if project not in built:
+ BuildProject(project, built, projects, deps)
+
+ print "-- --"
+
+def PrintVCProj(projects):
+
+ for project in projects:
+ print "-------------------------------------"
+ print "-------------------------------------"
+ print project
+ print project
+ print project
+ print "-------------------------------------"
+ print "-------------------------------------"
+
+ project_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[1]),
+ projects[project][2]))
+
+ pretty = pretty_vcproj
+ argv = [ '',
+ project_path,
+ '$(SolutionDir)=%s\\' % os.path.dirname(sys.argv[1]),
+ ]
+ argv.extend(sys.argv[3:])
+ pretty.main(argv)
+
+def main():
+ # check if we have exactly 1 parameter.
+ if len(sys.argv) < 2:
+ print 'Usage: %s "c:\\path\\to\\project.sln"' % sys.argv[0]
+ return
+
+ (projects, deps) = ParseSolution(sys.argv[1])
+ PrintDependencies(projects, deps)
+ PrintBuildOrder(projects, deps)
+
+ if '--recursive' in sys.argv:
+ PrintVCProj(projects)
+
+if __name__ == '__main__':
+ main()
+
diff --git a/Source/ThirdParty/gyp/tools/pretty_vcproj.py b/Source/ThirdParty/gyp/tools/pretty_vcproj.py
new file mode 100755
index 000000000..292a39f7c
--- /dev/null
+++ b/Source/ThirdParty/gyp/tools/pretty_vcproj.py
@@ -0,0 +1,316 @@
+#!/usr/bin/python2.5
+
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Make the format of a vcproj really pretty.
+
+ This script normalize and sort an xml. It also fetches all the properties
+ inside linked vsprops and include them explicitly in the vcproj.
+
+ It outputs the resulting xml to stdout.
+"""
+
+__author__ = 'nsylvain (Nicolas Sylvain)'
+
+import os
+import sys
+
+from xml.dom.minidom import parse
+from xml.dom.minidom import Node
+
+REPLACEMENTS = dict()
+ARGUMENTS = None
+
+class CmpTuple:
+ """Compare function between 2 tuple."""
+ def __call__(self, x, y):
+ (key1, value1) = x
+ (key2, value2) = y
+ return cmp(key1, key2)
+
+class CmpNode:
+ """Compare function between 2 xml nodes."""
+
+ def get_string(self, node):
+ node_string = "node"
+ node_string += node.nodeName
+ if node.nodeValue:
+ node_string += node.nodeValue
+
+ if node.attributes:
+ # We first sort by name, if present.
+ node_string += node.getAttribute("Name")
+
+ all_nodes = []
+ for (name, value) in node.attributes.items():
+ all_nodes.append((name, value))
+
+ all_nodes.sort(CmpTuple())
+ for (name, value) in all_nodes:
+ node_string += name
+ node_string += value
+
+ return node_string
+
+ def __call__(self, x, y):
+ return cmp(self.get_string(x), self.get_string(y))
+
+def PrettyPrintNode(node, indent=0):
+ if node.nodeType == Node.TEXT_NODE:
+ if node.data.strip():
+ print '%s%s' % (' '*indent, node.data.strip())
+ return
+
+ if node.childNodes:
+ node.normalize()
+ # Get the number of attributes
+ attr_count = 0
+ if node.attributes:
+ attr_count = node.attributes.length
+
+ # Print the main tag
+ if attr_count == 0:
+ print '%s<%s>' % (' '*indent, node.nodeName)
+ else:
+ print '%s<%s' % (' '*indent, node.nodeName)
+
+ all_attributes = []
+ for (name, value) in node.attributes.items():
+ all_attributes.append((name, value))
+ all_attributes.sort(CmpTuple())
+ for (name, value) in all_attributes:
+ print '%s %s="%s"' % (' '*indent, name, value)
+ print '%s>' % (' '*indent)
+ if node.nodeValue:
+ print '%s %s' % (' '*indent, node.nodeValue)
+
+ for sub_node in node.childNodes:
+ PrettyPrintNode(sub_node, indent=indent+2)
+ print '%s</%s>' % (' '*indent, node.nodeName)
+
+def FlattenFilter(node):
+ """Returns a list of all the node and sub nodes."""
+ node_list = []
+
+ if (node.attributes and
+ node.getAttribute('Name') == '_excluded_files'):
+ # We don't add the "_excluded_files" filter.
+ return []
+
+ for current in node.childNodes:
+ if current.nodeName == 'Filter':
+ node_list.extend(FlattenFilter(current))
+ else:
+ node_list.append(current)
+
+ return node_list
+
+def FixFilenames(filenames, current_directory):
+ new_list = []
+ for filename in filenames:
+ if filename:
+ for key in REPLACEMENTS:
+ filename = filename.replace(key, REPLACEMENTS[key])
+ os.chdir(current_directory)
+ filename = filename.strip('"\' ')
+ if filename.startswith('$'):
+ new_list.append(filename)
+ else:
+ new_list.append(os.path.abspath(filename))
+ return new_list
+
+def AbsoluteNode(node):
+ # Make all the properties we know about in this node absolute.
+ if node.attributes:
+ for (name, value) in node.attributes.items():
+ if name in ['InheritedPropertySheets', 'RelativePath',
+ 'AdditionalIncludeDirectories',
+ 'IntermediateDirectory', 'OutputDirectory',
+ 'AdditionalLibraryDirectories']:
+ # We want to fix up these paths
+ path_list = value.split(';')
+ new_list = FixFilenames(path_list, os.path.dirname(ARGUMENTS[1]))
+ node.setAttribute(name, ';'.join(new_list))
+ if not value:
+ node.removeAttribute(name)
+
+def CleanupVcproj(node):
+ # For each sub node, we call recursively this function.
+ for sub_node in node.childNodes:
+ AbsoluteNode(sub_node)
+ CleanupVcproj(sub_node)
+
+ # Normalize the node, and remove all extranous whitespaces.
+ for sub_node in node.childNodes:
+ if sub_node.nodeType == Node.TEXT_NODE:
+ sub_node.data = sub_node.data.replace("\r", "")
+ sub_node.data = sub_node.data.replace("\n", "")
+ sub_node.data = sub_node.data.rstrip()
+
+ # Fix all the semicolon separated attributes to be sorted, and we also
+ # remove the dups.
+ if node.attributes:
+ for (name, value) in node.attributes.items():
+ sorted_list = sorted(value.split(';'))
+ unique_list = []
+ [unique_list.append(i) for i in sorted_list if not unique_list.count(i)]
+ node.setAttribute(name, ';'.join(unique_list))
+ if not value:
+ node.removeAttribute(name)
+
+ if node.childNodes:
+ node.normalize()
+
+ # For each node, take a copy, and remove it from the list.
+ node_array = []
+ while node.childNodes and node.childNodes[0]:
+ # Take a copy of the node and remove it from the list.
+ current = node.childNodes[0]
+ node.removeChild(current)
+
+ # If the child is a filter, we want to append all its children
+ # to this same list.
+ if current.nodeName == 'Filter':
+ node_array.extend(FlattenFilter(current))
+ else:
+ node_array.append(current)
+
+
+ # Sort the list.
+ node_array.sort(CmpNode())
+
+ # Insert the nodes in the correct order.
+ for new_node in node_array:
+ # But don't append empty tool node.
+ if new_node.nodeName == 'Tool':
+ if new_node.attributes and new_node.attributes.length == 1:
+ # This one was empty.
+ continue
+ if new_node.nodeName == 'UserMacro':
+ continue
+ node.appendChild(new_node)
+
+def GetConfiguationNodes(vcproj):
+ #TODO(nsylvain): Find a better way to navigate the xml.
+ nodes = []
+ for node in vcproj.childNodes:
+ if node.nodeName == "Configurations":
+ for sub_node in node.childNodes:
+ if sub_node.nodeName == "Configuration":
+ nodes.append(sub_node)
+
+ return nodes
+
+def GetChildrenVsprops(filename):
+ dom = parse(filename)
+ if dom.documentElement.attributes:
+ vsprops = dom.documentElement.getAttribute('InheritedPropertySheets')
+ return FixFilenames(vsprops.split(';'), os.path.dirname(filename))
+ return []
+
+def SeekToNode(node1, child2):
+ # A text node does not have properties.
+ if child2.nodeType == Node.TEXT_NODE:
+ return None
+
+ # Get the name of the current node.
+ current_name = child2.getAttribute("Name")
+ if not current_name:
+ # There is no name. We don't know how to merge.
+ return None
+
+ # Look through all the nodes to find a match.
+ for sub_node in node1.childNodes:
+ if sub_node.nodeName == child2.nodeName:
+ name = sub_node.getAttribute("Name")
+ if name == current_name:
+ return sub_node
+
+ # No match. We give up.
+ return None
+
+def MergeAttributes(node1, node2):
+ # No attributes to merge?
+ if not node2.attributes:
+ return
+
+ for (name, value2) in node2.attributes.items():
+ # Don't merge the 'Name' attribute.
+ if name == 'Name':
+ continue
+ value1 = node1.getAttribute(name)
+ if value1:
+ # The attribute exist in the main node. If it's equal, we leave it
+ # untouched, otherwise we concatenate it.
+ if value1 != value2:
+ node1.setAttribute(name, ';'.join([value1, value2]))
+ else:
+ # The attribute does nto exist in the main node. We append this one.
+ node1.setAttribute(name, value2)
+
+ # If the attribute was a property sheet attributes, we remove it, since
+ # they are useless.
+ if name == 'InheritedPropertySheets':
+ node1.removeAttribute(name)
+
+def MergeProperties(node1, node2):
+ MergeAttributes(node1, node2)
+ for child2 in node2.childNodes:
+ child1 = SeekToNode(node1, child2)
+ if child1:
+ MergeProperties(child1, child2)
+ else:
+ node1.appendChild(child2.cloneNode(True))
+
+def main(argv):
+ global REPLACEMENTS
+ global ARGUMENTS
+ ARGUMENTS = argv
+ """Main function of this vcproj prettifier."""
+
+ # check if we have exactly 1 parameter.
+ if len(argv) < 2:
+ print ('Usage: %s "c:\\path\\to\\vcproj.vcproj" [key1=value1] '
+ '[key2=value2]' % argv[0])
+ return
+
+ # Parse the keys
+ for i in range(2, len(argv)):
+ (key, value) = argv[i].split('=')
+ REPLACEMENTS[key] = value
+
+ # Open the vcproj and parse the xml.
+ dom = parse(argv[1])
+
+ # First thing we need to do is find the Configuration Node and merge them
+ # with the vsprops they include.
+ for configuration_node in GetConfiguationNodes(dom.documentElement):
+ # Get the property sheets associated with this configuration.
+ vsprops = configuration_node.getAttribute('InheritedPropertySheets')
+
+ # Fix the filenames to be absolute.
+ vsprops_list = FixFilenames(vsprops.strip().split(';'),
+ os.path.dirname(argv[1]))
+
+ # Extend the list of vsprops with all vsprops contained in the current
+ # vsprops.
+ for current_vsprops in vsprops_list:
+ vsprops_list.extend(GetChildrenVsprops(current_vsprops))
+
+ # Now that we have all the vsprops, we need to merge them.
+ for current_vsprops in vsprops_list:
+ MergeProperties(configuration_node,
+ parse(current_vsprops).documentElement)
+
+ # Now that everything is merged, we need to cleanup the xml.
+ CleanupVcproj(dom.documentElement)
+
+ # Finally, we use the prett xml function to print the vcproj back to the
+ # user.
+ #print dom.toprettyxml(newl="\n")
+ PrettyPrintNode(dom.documentElement)
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/Source/ThirdParty/mt19937ar.c b/Source/ThirdParty/mt19937ar.c
new file mode 100644
index 000000000..4715958d1
--- /dev/null
+++ b/Source/ThirdParty/mt19937ar.c
@@ -0,0 +1,170 @@
+/*
+ A C-program for MT19937, with initialization improved 2002/1/26.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+
+ Before using, initialize the state by using init_genrand(seed)
+ or init_by_array(init_key, key_length).
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The names of its contributors may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+ Any feedback is very welcome.
+ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+#include <stdio.h>
+
+/* Period parameters */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL /* constant vector a */
+#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
+#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
+
+static unsigned long mt[N]; /* the array for the state vector */
+static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
+
+/* initializes mt[N] with a seed */
+void init_genrand(unsigned long s)
+{
+ mt[0]= s & 0xffffffffUL;
+ for (mti=1; mti<N; mti++) {
+ mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array mt[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ mt[mti] &= 0xffffffffUL;
+ /* for >32 bit machines */
+ }
+}
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+/* slight change for C++, 2004/2/26 */
+void init_by_array(unsigned long init_key[],int key_length)
+{
+ int i, j, k;
+ init_genrand(19650218UL);
+ i=1; j=0;
+ k = (N>key_length ? N : key_length);
+ for (; k; k--) {
+ mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ + init_key[j] + j; /* non linear */
+ mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+ i++; j++;
+ if (i>=N) { mt[0] = mt[N-1]; i=1; }
+ if (j>=key_length) j=0;
+ }
+ for (k=N-1; k; k--) {
+ mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
+ - i; /* non linear */
+ mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
+ i++;
+ if (i>=N) { mt[0] = mt[N-1]; i=1; }
+ }
+
+ mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
+}
+
+/* generates a random number on [0,0xffffffff]-interval */
+unsigned long genrand_int32(void)
+{
+ unsigned long y;
+ static unsigned long mag01[2]={0x0UL, MATRIX_A};
+ /* mag01[x] = x * MATRIX_A for x=0,1 */
+
+ if (mti >= N) { /* generate N words at one time */
+ int kk;
+
+ if (mti == N+1) /* if init_genrand() has not been called, */
+ init_genrand(5489UL); /* a default initial seed is used */
+
+ for (kk=0;kk<N-M;kk++) {
+ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
+ }
+ for (;kk<N-1;kk++) {
+ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
+ mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
+ }
+ y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
+ mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
+
+ mti = 0;
+ }
+
+ y = mt[mti++];
+
+ /* Tempering */
+ y ^= (y >> 11);
+ y ^= (y << 7) & 0x9d2c5680UL;
+ y ^= (y << 15) & 0xefc60000UL;
+ y ^= (y >> 18);
+
+ return y;
+}
+
+/* generates a random number on [0,0x7fffffff]-interval */
+long genrand_int31(void)
+{
+ return (long)(genrand_int32()>>1);
+}
+
+/* generates a random number on [0,1]-real-interval */
+double genrand_real1(void)
+{
+ return genrand_int32()*(1.0/4294967295.0);
+ /* divided by 2^32-1 */
+}
+
+/* generates a random number on [0,1)-real-interval */
+double genrand_real2(void)
+{
+ return genrand_int32()*(1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+/* generates a random number on (0,1)-real-interval */
+double genrand_real3(void)
+{
+ return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
+ /* divided by 2^32 */
+}
+
+/* generates a random number on [0,1) with 53-bit resolution*/
+double genrand_res53(void)
+{
+ unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
+ return(a*67108864.0+b)*(1.0/9007199254740992.0);
+}
diff --git a/Source/ThirdParty/qunit/.gitignore b/Source/ThirdParty/qunit/.gitignore
new file mode 100644
index 000000000..c6a02825e
--- /dev/null
+++ b/Source/ThirdParty/qunit/.gitignore
@@ -0,0 +1,6 @@
+.project
+*~
+*.diff
+*.patch
+.DS_Store
+
diff --git a/Source/ThirdParty/qunit/README.WebKit b/Source/ThirdParty/qunit/README.WebKit
new file mode 100644
index 000000000..210411ee2
--- /dev/null
+++ b/Source/ThirdParty/qunit/README.WebKit
@@ -0,0 +1,5 @@
+This direcotry was created using the following command:
+
+ git clone https://github.com/jquery/qunit.git
+
+Commit: b061e22c54f548fa2a768f14af5876c81ace5d09
diff --git a/Source/ThirdParty/qunit/README.md b/Source/ThirdParty/qunit/README.md
new file mode 100644
index 000000000..901d0b8ca
--- /dev/null
+++ b/Source/ThirdParty/qunit/README.md
@@ -0,0 +1,27 @@
+[QUnit](http://docs.jquery.com/QUnit) - A JavaScript Unit Testing framework.
+================================
+
+QUnit is a powerful, easy-to-use, JavaScript test suite. It's used by the jQuery
+project to test its code and plugins but is capable of testing any generic
+JavaScript code (and even capable of testing JavaScript code on the server-side).
+
+QUnit is especially useful for regression testing: Whenever a bug is reported,
+write a test that asserts the existence of that particular bug. Then fix it and
+commit both. Every time you work on the code again, run the tests. If the bug
+comes up again - a regression - you'll spot it immediately and know how to fix
+it, because you know what code you just changed.
+
+Having good unit test coverage makes safe refactoring easy and cheap. You can
+run the tests after each small refactoring step and always know what change
+broke something.
+
+QUnit is similar to other unit testing frameworks like JUnit, but makes use of
+the features JavaScript provides and helps with testing code in the browser, eg.
+with it's stop/start facilities for testing asynchronous code.
+
+If you are interested in helping developing QUnit, you are in the right place.
+For related discussions, visit the
+[QUnit and Testing forum](http://forum.jquery.com/qunit-and-testing).
+
+Planning for a qunitjs.com site and other testing tools related work now happens
+on the [jQuery Testing Team planning wiki](http://jquerytesting.pbworks.com/w/page/41556026/FrontPage).
diff --git a/Source/ThirdParty/qunit/package.json b/Source/ThirdParty/qunit/package.json
new file mode 100644
index 000000000..b6044c887
--- /dev/null
+++ b/Source/ThirdParty/qunit/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "qunit",
+ "author": {
+ "name": "John Resig",
+ "email": "jeresig@gmail.com",
+ "url": "http://ejohn.org/"
+ },
+ "maintainer": {
+ "name": "Jörn Zaefferer",
+ "email": "joern.zaefferer@googlemail.com",
+ "url": "http://bassistance.de/"
+ },
+ "url": "http://docs.jquery.com/QUnit",
+ "license": {
+ "name": "MIT",
+ "url": "http://www.opensource.org/licenses/mit-license.php"
+ },
+ "description": "An easy-to-use JavaScript Unit Testing framework.",
+ "keywords": [ "testing", "unit", "jquery" ],
+ "lib": "qunit"
+}
diff --git a/Source/ThirdParty/qunit/qunit/qunit.css b/Source/ThirdParty/qunit/qunit/qunit.css
new file mode 100644
index 000000000..b3c6db523
--- /dev/null
+++ b/Source/ThirdParty/qunit/qunit/qunit.css
@@ -0,0 +1,225 @@
+/**
+ * QUnit - A JavaScript Unit Testing Framework
+ *
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2011 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * or GPL (GPL-LICENSE.txt) licenses.
+ */
+
+/** Font Family and Sizes */
+
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
+}
+
+#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
+#qunit-tests { font-size: smaller; }
+
+
+/** Resets */
+
+#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
+ margin: 0;
+ padding: 0;
+}
+
+
+/** Header */
+
+#qunit-header {
+ padding: 0.5em 0 0.5em 1em;
+
+ color: #8699a4;
+ background-color: #0d3349;
+
+ font-size: 1.5em;
+ line-height: 1em;
+ font-weight: normal;
+
+ border-radius: 15px 15px 0 0;
+ -moz-border-radius: 15px 15px 0 0;
+ -webkit-border-top-right-radius: 15px;
+ -webkit-border-top-left-radius: 15px;
+}
+
+#qunit-header a {
+ text-decoration: none;
+ color: #c2ccd1;
+}
+
+#qunit-header a:hover,
+#qunit-header a:focus {
+ color: #fff;
+}
+
+#qunit-banner {
+ height: 5px;
+}
+
+#qunit-testrunner-toolbar {
+ padding: 0.5em 0 0.5em 2em;
+ color: #5E740B;
+ background-color: #eee;
+}
+
+#qunit-userAgent {
+ padding: 0.5em 0 0.5em 2.5em;
+ background-color: #2b81af;
+ color: #fff;
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
+}
+
+
+/** Tests: Pass/Fail */
+
+#qunit-tests {
+ list-style-position: inside;
+}
+
+#qunit-tests li {
+ padding: 0.4em 0.5em 0.4em 2.5em;
+ border-bottom: 1px solid #fff;
+ list-style-position: inside;
+}
+
+#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
+ display: none;
+}
+
+#qunit-tests li strong {
+ cursor: pointer;
+}
+
+#qunit-tests li a {
+ padding: 0.5em;
+ color: #c2ccd1;
+ text-decoration: none;
+}
+#qunit-tests li a:hover,
+#qunit-tests li a:focus {
+ color: #000;
+}
+
+#qunit-tests ol {
+ margin-top: 0.5em;
+ padding: 0.5em;
+
+ background-color: #fff;
+
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+
+ box-shadow: inset 0px 2px 13px #999;
+ -moz-box-shadow: inset 0px 2px 13px #999;
+ -webkit-box-shadow: inset 0px 2px 13px #999;
+}
+
+#qunit-tests table {
+ border-collapse: collapse;
+ margin-top: .2em;
+}
+
+#qunit-tests th {
+ text-align: right;
+ vertical-align: top;
+ padding: 0 .5em 0 0;
+}
+
+#qunit-tests td {
+ vertical-align: top;
+}
+
+#qunit-tests pre {
+ margin: 0;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+#qunit-tests del {
+ background-color: #e0f2be;
+ color: #374e0c;
+ text-decoration: none;
+}
+
+#qunit-tests ins {
+ background-color: #ffcaca;
+ color: #500;
+ text-decoration: none;
+}
+
+/*** Test Counts */
+
+#qunit-tests b.counts { color: black; }
+#qunit-tests b.passed { color: #5E740B; }
+#qunit-tests b.failed { color: #710909; }
+
+#qunit-tests li li {
+ margin: 0.5em;
+ padding: 0.4em 0.5em 0.4em 0.5em;
+ background-color: #fff;
+ border-bottom: none;
+ list-style-position: inside;
+}
+
+/*** Passing Styles */
+
+#qunit-tests li li.pass {
+ color: #5E740B;
+ background-color: #fff;
+ border-left: 26px solid #C6E746;
+}
+
+#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
+#qunit-tests .pass .test-name { color: #366097; }
+
+#qunit-tests .pass .test-actual,
+#qunit-tests .pass .test-expected { color: #999999; }
+
+#qunit-banner.qunit-pass { background-color: #C6E746; }
+
+/*** Failing Styles */
+
+#qunit-tests li li.fail {
+ color: #710909;
+ background-color: #fff;
+ border-left: 26px solid #EE5757;
+}
+
+#qunit-tests > li:last-child {
+ border-radius: 0 0 15px 15px;
+ -moz-border-radius: 0 0 15px 15px;
+ -webkit-border-bottom-right-radius: 15px;
+ -webkit-border-bottom-left-radius: 15px;
+}
+
+#qunit-tests .fail { color: #000000; background-color: #EE5757; }
+#qunit-tests .fail .test-name,
+#qunit-tests .fail .module-name { color: #000000; }
+
+#qunit-tests .fail .test-actual { color: #EE5757; }
+#qunit-tests .fail .test-expected { color: green; }
+
+#qunit-banner.qunit-fail { background-color: #EE5757; }
+
+
+/** Result */
+
+#qunit-testresult {
+ padding: 0.5em 0.5em 0.5em 2.5em;
+
+ color: #2b81af;
+ background-color: #D2E0E6;
+
+ border-bottom: 1px solid white;
+}
+
+/** Fixture */
+
+#qunit-fixture {
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+}
diff --git a/Source/ThirdParty/qunit/qunit/qunit.js b/Source/ThirdParty/qunit/qunit/qunit.js
new file mode 100644
index 000000000..e00cca902
--- /dev/null
+++ b/Source/ThirdParty/qunit/qunit/qunit.js
@@ -0,0 +1,1448 @@
+/**
+ * QUnit - A JavaScript Unit Testing Framework
+ *
+ * http://docs.jquery.com/QUnit
+ *
+ * Copyright (c) 2011 John Resig, Jörn Zaefferer
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * or GPL (GPL-LICENSE.txt) licenses.
+ */
+
+(function(window) {
+
+var defined = {
+ setTimeout: typeof window.setTimeout !== "undefined",
+ sessionStorage: (function() {
+ try {
+ return !!sessionStorage.getItem;
+ } catch(e){
+ return false;
+ }
+ })()
+};
+
+var testId = 0;
+
+var Test = function(name, testName, expected, testEnvironmentArg, async, callback) {
+ this.name = name;
+ this.testName = testName;
+ this.expected = expected;
+ this.testEnvironmentArg = testEnvironmentArg;
+ this.async = async;
+ this.callback = callback;
+ this.assertions = [];
+};
+Test.prototype = {
+ init: function() {
+ var tests = id("qunit-tests");
+ if (tests) {
+ var b = document.createElement("strong");
+ b.innerHTML = "Running " + this.name;
+ var li = document.createElement("li");
+ li.appendChild( b );
+ li.className = "running";
+ li.id = this.id = "test-output" + testId++;
+ tests.appendChild( li );
+ }
+ },
+ setup: function() {
+ if (this.module != config.previousModule) {
+ if ( config.previousModule ) {
+ QUnit.moduleDone( {
+ name: config.previousModule,
+ failed: config.moduleStats.bad,
+ passed: config.moduleStats.all - config.moduleStats.bad,
+ total: config.moduleStats.all
+ } );
+ }
+ config.previousModule = this.module;
+ config.moduleStats = { all: 0, bad: 0 };
+ QUnit.moduleStart( {
+ name: this.module
+ } );
+ }
+
+ config.current = this;
+ this.testEnvironment = extend({
+ setup: function() {},
+ teardown: function() {}
+ }, this.moduleTestEnvironment);
+ if (this.testEnvironmentArg) {
+ extend(this.testEnvironment, this.testEnvironmentArg);
+ }
+
+ QUnit.testStart( {
+ name: this.testName
+ } );
+
+ // allow utility functions to access the current test environment
+ // TODO why??
+ QUnit.current_testEnvironment = this.testEnvironment;
+
+ try {
+ if ( !config.pollution ) {
+ saveGlobal();
+ }
+
+ this.testEnvironment.setup.call(this.testEnvironment);
+ } catch(e) {
+ QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message );
+ }
+ },
+ run: function() {
+ if ( this.async ) {
+ QUnit.stop();
+ }
+
+ if ( config.notrycatch ) {
+ this.callback.call(this.testEnvironment);
+ return;
+ }
+ try {
+ this.callback.call(this.testEnvironment);
+ } catch(e) {
+ fail("Test " + this.testName + " died, exception and test follows", e, this.callback);
+ QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) );
+ // else next test will carry the responsibility
+ saveGlobal();
+
+ // Restart the tests if they're blocking
+ if ( config.blocking ) {
+ start();
+ }
+ }
+ },
+ teardown: function() {
+ try {
+ this.testEnvironment.teardown.call(this.testEnvironment);
+ checkPollution();
+ } catch(e) {
+ QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message );
+ }
+ },
+ finish: function() {
+ if ( this.expected && this.expected != this.assertions.length ) {
+ QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" );
+ }
+
+ var good = 0, bad = 0,
+ tests = id("qunit-tests");
+
+ config.stats.all += this.assertions.length;
+ config.moduleStats.all += this.assertions.length;
+
+ if ( tests ) {
+ var ol = document.createElement("ol");
+
+ for ( var i = 0; i < this.assertions.length; i++ ) {
+ var assertion = this.assertions[i];
+
+ var li = document.createElement("li");
+ li.className = assertion.result ? "pass" : "fail";
+ li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed");
+ ol.appendChild( li );
+
+ if ( assertion.result ) {
+ good++;
+ } else {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+
+ // store result when possible
+ if ( QUnit.config.reorder && defined.sessionStorage ) {
+ if (bad) {
+ sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad);
+ } else {
+ sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName);
+ }
+ }
+
+ if (bad == 0) {
+ ol.style.display = "none";
+ }
+
+ var b = document.createElement("strong");
+ b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
+
+ var a = document.createElement("a");
+ a.innerHTML = "Rerun";
+ a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
+
+ addEvent(b, "click", function() {
+ var next = b.nextSibling.nextSibling,
+ display = next.style.display;
+ next.style.display = display === "none" ? "block" : "none";
+ });
+
+ addEvent(b, "dblclick", function(e) {
+ var target = e && e.target ? e.target : window.event.srcElement;
+ if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) {
+ target = target.parentNode;
+ }
+ if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
+ window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") });
+ }
+ });
+
+ var li = id(this.id);
+ li.className = bad ? "fail" : "pass";
+ li.removeChild( li.firstChild );
+ li.appendChild( b );
+ li.appendChild( a );
+ li.appendChild( ol );
+
+ } else {
+ for ( var i = 0; i < this.assertions.length; i++ ) {
+ if ( !this.assertions[i].result ) {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+ }
+
+ try {
+ QUnit.reset();
+ } catch(e) {
+ fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset);
+ }
+
+ QUnit.testDone( {
+ name: this.testName,
+ failed: bad,
+ passed: this.assertions.length - bad,
+ total: this.assertions.length
+ } );
+ },
+
+ queue: function() {
+ var test = this;
+ synchronize(function() {
+ test.init();
+ });
+ function run() {
+ // each of these can by async
+ synchronize(function() {
+ test.setup();
+ });
+ synchronize(function() {
+ test.run();
+ });
+ synchronize(function() {
+ test.teardown();
+ });
+ synchronize(function() {
+ test.finish();
+ });
+ }
+ // defer when previous test run passed, if storage is available
+ var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName);
+ if (bad) {
+ run();
+ } else {
+ synchronize(run);
+ };
+ }
+
+};
+
+var QUnit = {
+
+ // call on start of module test to prepend name to all tests
+ module: function(name, testEnvironment) {
+ config.currentModule = name;
+ config.currentModuleTestEnviroment = testEnvironment;
+ },
+
+ asyncTest: function(testName, expected, callback) {
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = 0;
+ }
+
+ QUnit.test(testName, expected, callback, true);
+ },
+
+ test: function(testName, expected, callback, async) {
+ var name = '<span class="test-name">' + testName + '</span>', testEnvironmentArg;
+
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = null;
+ }
+ // is 2nd argument a testEnvironment?
+ if ( expected && typeof expected === 'object') {
+ testEnvironmentArg = expected;
+ expected = null;
+ }
+
+ if ( config.currentModule ) {
+ name = '<span class="module-name">' + config.currentModule + "</span>: " + name;
+ }
+
+ if ( !validTest(config.currentModule + ": " + testName) ) {
+ return;
+ }
+
+ var test = new Test(name, testName, expected, testEnvironmentArg, async, callback);
+ test.module = config.currentModule;
+ test.moduleTestEnvironment = config.currentModuleTestEnviroment;
+ test.queue();
+ },
+
+ /**
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
+ */
+ expect: function(asserts) {
+ config.current.expected = asserts;
+ },
+
+ /**
+ * Asserts true.
+ * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
+ */
+ ok: function(a, msg) {
+ a = !!a;
+ var details = {
+ result: a,
+ message: msg
+ };
+ msg = escapeHtml(msg);
+ QUnit.log(details);
+ config.current.assertions.push({
+ result: a,
+ message: msg
+ });
+ },
+
+ /**
+ * Checks that the first two arguments are equal, with an optional message.
+ * Prints out both actual and expected values.
+ *
+ * Prefered to ok( actual == expected, message )
+ *
+ * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." );
+ *
+ * @param Object actual
+ * @param Object expected
+ * @param String message (optional)
+ */
+ equal: function(actual, expected, message) {
+ QUnit.push(expected == actual, actual, expected, message);
+ },
+
+ notEqual: function(actual, expected, message) {
+ QUnit.push(expected != actual, actual, expected, message);
+ },
+
+ deepEqual: function(actual, expected, message) {
+ QUnit.push(QUnit.equiv(actual, expected), actual, expected, message);
+ },
+
+ notDeepEqual: function(actual, expected, message) {
+ QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message);
+ },
+
+ strictEqual: function(actual, expected, message) {
+ QUnit.push(expected === actual, actual, expected, message);
+ },
+
+ notStrictEqual: function(actual, expected, message) {
+ QUnit.push(expected !== actual, actual, expected, message);
+ },
+
+ raises: function(block, expected, message) {
+ var actual, ok = false;
+
+ if (typeof expected === 'string') {
+ message = expected;
+ expected = null;
+ }
+
+ try {
+ block();
+ } catch (e) {
+ actual = e;
+ }
+
+ if (actual) {
+ // we don't want to validate thrown error
+ if (!expected) {
+ ok = true;
+ // expected is a regexp
+ } else if (QUnit.objectType(expected) === "regexp") {
+ ok = expected.test(actual);
+ // expected is a constructor
+ } else if (actual instanceof expected) {
+ ok = true;
+ // expected is a validation function which returns true is validation passed
+ } else if (expected.call({}, actual) === true) {
+ ok = true;
+ }
+ }
+
+ QUnit.ok(ok, message);
+ },
+
+ start: function() {
+ config.semaphore--;
+ if (config.semaphore > 0) {
+ // don't start until equal number of stop-calls
+ return;
+ }
+ if (config.semaphore < 0) {
+ // ignore if start is called more often then stop
+ config.semaphore = 0;
+ }
+ // A slight delay, to avoid any current callbacks
+ if ( defined.setTimeout ) {
+ window.setTimeout(function() {
+ if ( config.timeout ) {
+ clearTimeout(config.timeout);
+ }
+
+ config.blocking = false;
+ process();
+ }, 13);
+ } else {
+ config.blocking = false;
+ process();
+ }
+ },
+
+ stop: function(timeout) {
+ config.semaphore++;
+ config.blocking = true;
+
+ if ( timeout && defined.setTimeout ) {
+ clearTimeout(config.timeout);
+ config.timeout = window.setTimeout(function() {
+ QUnit.ok( false, "Test timed out" );
+ QUnit.start();
+ }, timeout);
+ }
+ }
+};
+
+// Backwards compatibility, deprecated
+QUnit.equals = QUnit.equal;
+QUnit.same = QUnit.deepEqual;
+
+// Maintain internal state
+var config = {
+ // The queue of tests to run
+ queue: [],
+
+ // block until document ready
+ blocking: true,
+
+ // by default, run previously failed tests first
+ // very useful in combination with "Hide passed tests" checked
+ reorder: true,
+
+ noglobals: false,
+ notrycatch: false
+};
+
+// Load paramaters
+(function() {
+ var location = window.location || { search: "", protocol: "file:" },
+ params = location.search.slice( 1 ).split( "&" ),
+ length = params.length,
+ urlParams = {},
+ current;
+
+ if ( params[ 0 ] ) {
+ for ( var i = 0; i < length; i++ ) {
+ current = params[ i ].split( "=" );
+ current[ 0 ] = decodeURIComponent( current[ 0 ] );
+ // allow just a key to turn on a flag, e.g., test.html?noglobals
+ current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
+ urlParams[ current[ 0 ] ] = current[ 1 ];
+ if ( current[ 0 ] in config ) {
+ config[ current[ 0 ] ] = current[ 1 ];
+ }
+ }
+ }
+
+ QUnit.urlParams = urlParams;
+ config.filter = urlParams.filter;
+
+ // Figure out if we're running the tests from a server or not
+ QUnit.isLocal = !!(location.protocol === 'file:');
+})();
+
+// Expose the API as global variables, unless an 'exports'
+// object exists, in that case we assume we're in CommonJS
+if ( typeof exports === "undefined" || typeof require === "undefined" ) {
+ extend(window, QUnit);
+ window.QUnit = QUnit;
+} else {
+ extend(exports, QUnit);
+ exports.QUnit = QUnit;
+}
+
+// define these after exposing globals to keep them in these QUnit namespace only
+extend(QUnit, {
+ config: config,
+
+ // Initialize the configuration options
+ init: function() {
+ extend(config, {
+ stats: { all: 0, bad: 0 },
+ moduleStats: { all: 0, bad: 0 },
+ started: +new Date,
+ updateRate: 1000,
+ blocking: false,
+ autostart: true,
+ autorun: false,
+ filter: "",
+ queue: [],
+ semaphore: 0
+ });
+
+ var tests = id( "qunit-tests" ),
+ banner = id( "qunit-banner" ),
+ result = id( "qunit-testresult" );
+
+ if ( tests ) {
+ tests.innerHTML = "";
+ }
+
+ if ( banner ) {
+ banner.className = "";
+ }
+
+ if ( result ) {
+ result.parentNode.removeChild( result );
+ }
+
+ if ( tests ) {
+ result = document.createElement( "p" );
+ result.id = "qunit-testresult";
+ result.className = "result";
+ tests.parentNode.insertBefore( result, tests );
+ result.innerHTML = 'Running...<br/>&nbsp;';
+ }
+ },
+
+ /**
+ * Resets the test setup. Useful for tests that modify the DOM.
+ *
+ * If jQuery is available, uses jQuery's html(), otherwise just innerHTML.
+ */
+ reset: function() {
+ if ( window.jQuery ) {
+ jQuery( "#qunit-fixture" ).html( config.fixture );
+ } else {
+ var main = id( 'qunit-fixture' );
+ if ( main ) {
+ main.innerHTML = config.fixture;
+ }
+ }
+ },
+
+ /**
+ * Trigger an event on an element.
+ *
+ * @example triggerEvent( document.body, "click" );
+ *
+ * @param DOMElement elem
+ * @param String type
+ */
+ triggerEvent: function( elem, type, event ) {
+ if ( document.createEvent ) {
+ event = document.createEvent("MouseEvents");
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ elem.dispatchEvent( event );
+
+ } else if ( elem.fireEvent ) {
+ elem.fireEvent("on"+type);
+ }
+ },
+
+ // Safe object type checking
+ is: function( type, obj ) {
+ return QUnit.objectType( obj ) == type;
+ },
+
+ objectType: function( obj ) {
+ if (typeof obj === "undefined") {
+ return "undefined";
+
+ // consider: typeof null === object
+ }
+ if (obj === null) {
+ return "null";
+ }
+
+ var type = Object.prototype.toString.call( obj )
+ .match(/^\[object\s(.*)\]$/)[1] || '';
+
+ switch (type) {
+ case 'Number':
+ if (isNaN(obj)) {
+ return "nan";
+ } else {
+ return "number";
+ }
+ case 'String':
+ case 'Boolean':
+ case 'Array':
+ case 'Date':
+ case 'RegExp':
+ case 'Function':
+ return type.toLowerCase();
+ }
+ if (typeof obj === "object") {
+ return "object";
+ }
+ return undefined;
+ },
+
+ push: function(result, actual, expected, message) {
+ var details = {
+ result: result,
+ message: message,
+ actual: actual,
+ expected: expected
+ };
+
+ message = escapeHtml(message) || (result ? "okay" : "failed");
+ message = '<span class="test-message">' + message + "</span>";
+ expected = escapeHtml(QUnit.jsDump.parse(expected));
+ actual = escapeHtml(QUnit.jsDump.parse(actual));
+ var output = message + '<table><tr class="test-expected"><th>Expected: </th><td><pre>' + expected + '</pre></td></tr>';
+ if (actual != expected) {
+ output += '<tr class="test-actual"><th>Result: </th><td><pre>' + actual + '</pre></td></tr>';
+ output += '<tr class="test-diff"><th>Diff: </th><td><pre>' + QUnit.diff(expected, actual) +'</pre></td></tr>';
+ }
+ if (!result) {
+ var source = sourceFromStacktrace();
+ if (source) {
+ details.source = source;
+ output += '<tr class="test-source"><th>Source: </th><td><pre>' + escapeHtml(source) + '</pre></td></tr>';
+ }
+ }
+ output += "</table>";
+
+ QUnit.log(details);
+
+ config.current.assertions.push({
+ result: !!result,
+ message: output
+ });
+ },
+
+ url: function( params ) {
+ params = extend( extend( {}, QUnit.urlParams ), params );
+ var querystring = "?",
+ key;
+ for ( key in params ) {
+ querystring += encodeURIComponent( key ) + "=" +
+ encodeURIComponent( params[ key ] ) + "&";
+ }
+ return window.location.pathname + querystring.slice( 0, -1 );
+ },
+
+ // Logging callbacks; all receive a single argument with the listed properties
+ // run test/logs.html for any related changes
+ begin: function() {},
+ // done: { failed, passed, total, runtime }
+ done: function() {},
+ // log: { result, actual, expected, message }
+ log: function() {},
+ // testStart: { name }
+ testStart: function() {},
+ // testDone: { name, failed, passed, total }
+ testDone: function() {},
+ // moduleStart: { name }
+ moduleStart: function() {},
+ // moduleDone: { name, failed, passed, total }
+ moduleDone: function() {}
+});
+
+if ( typeof document === "undefined" || document.readyState === "complete" ) {
+ config.autorun = true;
+}
+
+addEvent(window, "load", function() {
+ QUnit.begin({});
+
+ // Initialize the config, saving the execution queue
+ var oldconfig = extend({}, config);
+ QUnit.init();
+ extend(config, oldconfig);
+
+ config.blocking = false;
+
+ var userAgent = id("qunit-userAgent");
+ if ( userAgent ) {
+ userAgent.innerHTML = navigator.userAgent;
+ }
+ var banner = id("qunit-header");
+ if ( banner ) {
+ banner.innerHTML = '<a href="' + QUnit.url({ filter: undefined }) + '"> ' + banner.innerHTML + '</a> ' +
+ '<label><input name="noglobals" type="checkbox"' + ( config.noglobals ? ' checked="checked"' : '' ) + '>noglobals</label>' +
+ '<label><input name="notrycatch" type="checkbox"' + ( config.notrycatch ? ' checked="checked"' : '' ) + '>notrycatch</label>';
+ addEvent( banner, "change", function( event ) {
+ var params = {};
+ params[ event.target.name ] = event.target.checked ? true : undefined;
+ window.location = QUnit.url( params );
+ });
+ }
+
+ var toolbar = id("qunit-testrunner-toolbar");
+ if ( toolbar ) {
+ var filter = document.createElement("input");
+ filter.type = "checkbox";
+ filter.id = "qunit-filter-pass";
+ addEvent( filter, "click", function() {
+ var ol = document.getElementById("qunit-tests");
+ if ( filter.checked ) {
+ ol.className = ol.className + " hidepass";
+ } else {
+ var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
+ ol.className = tmp.replace(/ hidepass /, " ");
+ }
+ if ( defined.sessionStorage ) {
+ if (filter.checked) {
+ sessionStorage.setItem("qunit-filter-passed-tests", "true");
+ } else {
+ sessionStorage.removeItem("qunit-filter-passed-tests");
+ }
+ }
+ });
+ if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
+ filter.checked = true;
+ var ol = document.getElementById("qunit-tests");
+ ol.className = ol.className + " hidepass";
+ }
+ toolbar.appendChild( filter );
+
+ var label = document.createElement("label");
+ label.setAttribute("for", "qunit-filter-pass");
+ label.innerHTML = "Hide passed tests";
+ toolbar.appendChild( label );
+ }
+
+ var main = id('qunit-fixture');
+ if ( main ) {
+ config.fixture = main.innerHTML;
+ }
+
+ if (config.autostart) {
+ QUnit.start();
+ }
+});
+
+function done() {
+ config.autorun = true;
+
+ // Log the last module results
+ if ( config.currentModule ) {
+ QUnit.moduleDone( {
+ name: config.currentModule,
+ failed: config.moduleStats.bad,
+ passed: config.moduleStats.all - config.moduleStats.bad,
+ total: config.moduleStats.all
+ } );
+ }
+
+ var banner = id("qunit-banner"),
+ tests = id("qunit-tests"),
+ runtime = +new Date - config.started,
+ passed = config.stats.all - config.stats.bad,
+ html = [
+ 'Tests completed in ',
+ runtime,
+ ' milliseconds.<br/>',
+ '<span class="passed">',
+ passed,
+ '</span> tests of <span class="total">',
+ config.stats.all,
+ '</span> passed, <span class="failed">',
+ config.stats.bad,
+ '</span> failed.'
+ ].join('');
+
+ if ( banner ) {
+ banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
+ }
+
+ if ( tests ) {
+ id( "qunit-testresult" ).innerHTML = html;
+ }
+
+ if ( typeof document !== "undefined" && document.title ) {
+ // show ✖ for good, ✔ for bad suite result in title
+ // use escape sequences in case file gets loaded with non-utf-8-charset
+ document.title = (config.stats.bad ? "\u2716" : "\u2714") + " " + document.title;
+ }
+
+ QUnit.done( {
+ failed: config.stats.bad,
+ passed: passed,
+ total: config.stats.all,
+ runtime: runtime
+ } );
+}
+
+function validTest( name ) {
+ var filter = config.filter,
+ run = false;
+
+ if ( !filter ) {
+ return true;
+ }
+
+ var not = filter.charAt( 0 ) === "!";
+ if ( not ) {
+ filter = filter.slice( 1 );
+ }
+
+ if ( name.indexOf( filter ) !== -1 ) {
+ return !not;
+ }
+
+ if ( not ) {
+ run = true;
+ }
+
+ return run;
+}
+
+// so far supports only Firefox, Chrome and Opera (buggy)
+// could be extended in the future to use something like https://github.com/csnover/TraceKit
+function sourceFromStacktrace() {
+ try {
+ throw new Error();
+ } catch ( e ) {
+ if (e.stacktrace) {
+ // Opera
+ return e.stacktrace.split("\n")[6];
+ } else if (e.stack) {
+ // Firefox, Chrome
+ return e.stack.split("\n")[4];
+ }
+ }
+}
+
+function escapeHtml(s) {
+ if (!s) {
+ return "";
+ }
+ s = s + "";
+ return s.replace(/[\&"<>\\]/g, function(s) {
+ switch(s) {
+ case "&": return "&amp;";
+ case "\\": return "\\\\";
+ case '"': return '\"';
+ case "<": return "&lt;";
+ case ">": return "&gt;";
+ default: return s;
+ }
+ });
+}
+
+function synchronize( callback ) {
+ config.queue.push( callback );
+
+ if ( config.autorun && !config.blocking ) {
+ process();
+ }
+}
+
+function process() {
+ var start = (new Date()).getTime();
+
+ while ( config.queue.length && !config.blocking ) {
+ if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
+ config.queue.shift()();
+ } else {
+ window.setTimeout( process, 13 );
+ break;
+ }
+ }
+ if (!config.blocking && !config.queue.length) {
+ done();
+ }
+}
+
+function saveGlobal() {
+ config.pollution = [];
+
+ if ( config.noglobals ) {
+ for ( var key in window ) {
+ config.pollution.push( key );
+ }
+ }
+}
+
+function checkPollution( name ) {
+ var old = config.pollution;
+ saveGlobal();
+
+ var newGlobals = diff( config.pollution, old );
+ if ( newGlobals.length > 0 ) {
+ ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
+ }
+
+ var deletedGlobals = diff( old, config.pollution );
+ if ( deletedGlobals.length > 0 ) {
+ ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
+ }
+}
+
+// returns a new Array with the elements that are in a but not in b
+function diff( a, b ) {
+ var result = a.slice();
+ for ( var i = 0; i < result.length; i++ ) {
+ for ( var j = 0; j < b.length; j++ ) {
+ if ( result[i] === b[j] ) {
+ result.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+function fail(message, exception, callback) {
+ if ( typeof console !== "undefined" && console.error && console.warn ) {
+ console.error(message);
+ console.error(exception);
+ console.warn(callback.toString());
+
+ } else if ( window.opera && opera.postError ) {
+ opera.postError(message, exception, callback.toString);
+ }
+}
+
+function extend(a, b) {
+ for ( var prop in b ) {
+ if ( b[prop] === undefined ) {
+ delete a[prop];
+ } else {
+ a[prop] = b[prop];
+ }
+ }
+
+ return a;
+}
+
+function addEvent(elem, type, fn) {
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, fn, false );
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, fn );
+ } else {
+ fn();
+ }
+}
+
+function id(name) {
+ return !!(typeof document !== "undefined" && document && document.getElementById) &&
+ document.getElementById( name );
+}
+
+// Test for equality any JavaScript type.
+// Discussions and reference: http://philrathe.com/articles/equiv
+// Test suites: http://philrathe.com/tests/equiv
+// Author: Philippe Rathé <prathe@gmail.com>
+QUnit.equiv = function () {
+
+ var innerEquiv; // the real equiv function
+ var callers = []; // stack to decide between skip/abort functions
+ var parents = []; // stack to avoiding loops from circular referencing
+
+ // Call the o related callback with the given arguments.
+ function bindCallbacks(o, callbacks, args) {
+ var prop = QUnit.objectType(o);
+ if (prop) {
+ if (QUnit.objectType(callbacks[prop]) === "function") {
+ return callbacks[prop].apply(callbacks, args);
+ } else {
+ return callbacks[prop]; // or undefined
+ }
+ }
+ }
+
+ var callbacks = function () {
+
+ // for string, boolean, number and null
+ function useStrictEquality(b, a) {
+ if (b instanceof a.constructor || a instanceof b.constructor) {
+ // to catch short annotaion VS 'new' annotation of a declaration
+ // e.g. var i = 1;
+ // var j = new Number(1);
+ return a == b;
+ } else {
+ return a === b;
+ }
+ }
+
+ return {
+ "string": useStrictEquality,
+ "boolean": useStrictEquality,
+ "number": useStrictEquality,
+ "null": useStrictEquality,
+ "undefined": useStrictEquality,
+
+ "nan": function (b) {
+ return isNaN(b);
+ },
+
+ "date": function (b, a) {
+ return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
+ },
+
+ "regexp": function (b, a) {
+ return QUnit.objectType(b) === "regexp" &&
+ a.source === b.source && // the regex itself
+ a.global === b.global && // and its modifers (gmi) ...
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline;
+ },
+
+ // - skip when the property is a method of an instance (OOP)
+ // - abort otherwise,
+ // initial === would have catch identical references anyway
+ "function": function () {
+ var caller = callers[callers.length - 1];
+ return caller !== Object &&
+ typeof caller !== "undefined";
+ },
+
+ "array": function (b, a) {
+ var i, j, loop;
+ var len;
+
+ // b could be an object literal here
+ if ( ! (QUnit.objectType(b) === "array")) {
+ return false;
+ }
+
+ len = a.length;
+ if (len !== b.length) { // safe and faster
+ return false;
+ }
+
+ //track reference to avoid circular references
+ parents.push(a);
+ for (i = 0; i < len; i++) {
+ loop = false;
+ for(j=0;j<parents.length;j++){
+ if(parents[j] === a[i]){
+ loop = true;//dont rewalk array
+ }
+ }
+ if (!loop && ! innerEquiv(a[i], b[i])) {
+ parents.pop();
+ return false;
+ }
+ }
+ parents.pop();
+ return true;
+ },
+
+ "object": function (b, a) {
+ var i, j, loop;
+ var eq = true; // unless we can proove it
+ var aProperties = [], bProperties = []; // collection of strings
+
+ // comparing constructors is more strict than using instanceof
+ if ( a.constructor !== b.constructor) {
+ return false;
+ }
+
+ // stack constructor before traversing properties
+ callers.push(a.constructor);
+ //track reference to avoid circular references
+ parents.push(a);
+
+ for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
+ loop = false;
+ for(j=0;j<parents.length;j++){
+ if(parents[j] === a[i])
+ loop = true; //don't go down the same path twice
+ }
+ aProperties.push(i); // collect a's properties
+
+ if (!loop && ! innerEquiv(a[i], b[i])) {
+ eq = false;
+ break;
+ }
+ }
+
+ callers.pop(); // unstack, we are done
+ parents.pop();
+
+ for (i in b) {
+ bProperties.push(i); // collect b's properties
+ }
+
+ // Ensures identical properties name
+ return eq && innerEquiv(aProperties.sort(), bProperties.sort());
+ }
+ };
+ }();
+
+ innerEquiv = function () { // can take multiple arguments
+ var args = Array.prototype.slice.apply(arguments);
+ if (args.length < 2) {
+ return true; // end transition
+ }
+
+ return (function (a, b) {
+ if (a === b) {
+ return true; // catch the most you can
+ } else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || QUnit.objectType(a) !== QUnit.objectType(b)) {
+ return false; // don't lose time with error prone cases
+ } else {
+ return bindCallbacks(a, callbacks, [b, a]);
+ }
+
+ // apply transition with (1..n) arguments
+ })(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
+ };
+
+ return innerEquiv;
+
+}();
+
+/**
+ * jsDump
+ * Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
+ * Date: 5/15/2008
+ * @projectDescription Advanced and extensible data dumping for Javascript.
+ * @version 1.0.0
+ * @author Ariel Flesler
+ * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
+ */
+QUnit.jsDump = (function() {
+ function quote( str ) {
+ return '"' + str.toString().replace(/"/g, '\\"') + '"';
+ };
+ function literal( o ) {
+ return o + '';
+ };
+ function join( pre, arr, post ) {
+ var s = jsDump.separator(),
+ base = jsDump.indent(),
+ inner = jsDump.indent(1);
+ if ( arr.join )
+ arr = arr.join( ',' + s + inner );
+ if ( !arr )
+ return pre + post;
+ return [ pre, inner + arr, base + post ].join(s);
+ };
+ function array( arr ) {
+ var i = arr.length, ret = Array(i);
+ this.up();
+ while ( i-- )
+ ret[i] = this.parse( arr[i] );
+ this.down();
+ return join( '[', ret, ']' );
+ };
+
+ var reName = /^function (\w+)/;
+
+ var jsDump = {
+ parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
+ var parser = this.parsers[ type || this.typeOf(obj) ];
+ type = typeof parser;
+
+ return type == 'function' ? parser.call( this, obj ) :
+ type == 'string' ? parser :
+ this.parsers.error;
+ },
+ typeOf:function( obj ) {
+ var type;
+ if ( obj === null ) {
+ type = "null";
+ } else if (typeof obj === "undefined") {
+ type = "undefined";
+ } else if (QUnit.is("RegExp", obj)) {
+ type = "regexp";
+ } else if (QUnit.is("Date", obj)) {
+ type = "date";
+ } else if (QUnit.is("Function", obj)) {
+ type = "function";
+ } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") {
+ type = "window";
+ } else if (obj.nodeType === 9) {
+ type = "document";
+ } else if (obj.nodeType) {
+ type = "node";
+ } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) {
+ type = "array";
+ } else {
+ type = typeof obj;
+ }
+ return type;
+ },
+ separator:function() {
+ return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? '&nbsp;' : ' ';
+ },
+ indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
+ if ( !this.multiline )
+ return '';
+ var chr = this.indentChar;
+ if ( this.HTML )
+ chr = chr.replace(/\t/g,' ').replace(/ /g,'&nbsp;');
+ return Array( this._depth_ + (extra||0) ).join(chr);
+ },
+ up:function( a ) {
+ this._depth_ += a || 1;
+ },
+ down:function( a ) {
+ this._depth_ -= a || 1;
+ },
+ setParser:function( name, parser ) {
+ this.parsers[name] = parser;
+ },
+ // The next 3 are exposed so you can use them
+ quote:quote,
+ literal:literal,
+ join:join,
+ //
+ _depth_: 1,
+ // This is the list of parsers, to modify them, use jsDump.setParser
+ parsers:{
+ window: '[Window]',
+ document: '[Document]',
+ error:'[ERROR]', //when no parser is found, shouldn't happen
+ unknown: '[Unknown]',
+ 'null':'null',
+ 'undefined':'undefined',
+ 'function':function( fn ) {
+ var ret = 'function',
+ name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
+ if ( name )
+ ret += ' ' + name;
+ ret += '(';
+
+ ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
+ return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
+ },
+ array: array,
+ nodelist: array,
+ arguments: array,
+ object:function( map ) {
+ var ret = [ ];
+ QUnit.jsDump.up();
+ for ( var key in map )
+ ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) );
+ QUnit.jsDump.down();
+ return join( '{', ret, '}' );
+ },
+ node:function( node ) {
+ var open = QUnit.jsDump.HTML ? '&lt;' : '<',
+ close = QUnit.jsDump.HTML ? '&gt;' : '>';
+
+ var tag = node.nodeName.toLowerCase(),
+ ret = open + tag;
+
+ for ( var a in QUnit.jsDump.DOMAttrs ) {
+ var val = node[QUnit.jsDump.DOMAttrs[a]];
+ if ( val )
+ ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
+ }
+ return ret + close + open + '/' + tag + close;
+ },
+ functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
+ var l = fn.length;
+ if ( !l ) return '';
+
+ var args = Array(l);
+ while ( l-- )
+ args[l] = String.fromCharCode(97+l);//97 is 'a'
+ return ' ' + args.join(', ') + ' ';
+ },
+ key:quote, //object calls it internally, the key part of an item in a map
+ functionCode:'[code]', //function calls it internally, it's the content of the function
+ attribute:quote, //node calls it internally, it's an html attribute value
+ string:quote,
+ date:quote,
+ regexp:literal, //regex
+ number:literal,
+ 'boolean':literal
+ },
+ DOMAttrs:{//attributes to dump from nodes, name=>realName
+ id:'id',
+ name:'name',
+ 'class':'className'
+ },
+ HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
+ indentChar:' ',//indentation unit
+ multiline:true //if true, items in a collection, are separated by a \n, else just a space.
+ };
+
+ return jsDump;
+})();
+
+// from Sizzle.js
+function getText( elems ) {
+ var ret = "", elem;
+
+ for ( var i = 0; elems[i]; i++ ) {
+ elem = elems[i];
+
+ // Get the text from text nodes and CDATA nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+ ret += elem.nodeValue;
+
+ // Traverse everything else, except comment nodes
+ } else if ( elem.nodeType !== 8 ) {
+ ret += getText( elem.childNodes );
+ }
+ }
+
+ return ret;
+};
+
+/*
+ * Javascript Diff Algorithm
+ * By John Resig (http://ejohn.org/)
+ * Modified by Chu Alan "sprite"
+ *
+ * Released under the MIT license.
+ *
+ * More Info:
+ * http://ejohn.org/projects/javascript-diff-algorithm/
+ *
+ * Usage: QUnit.diff(expected, actual)
+ *
+ * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
+ */
+QUnit.diff = (function() {
+ function diff(o, n){
+ var ns = new Object();
+ var os = new Object();
+
+ for (var i = 0; i < n.length; i++) {
+ if (ns[n[i]] == null)
+ ns[n[i]] = {
+ rows: new Array(),
+ o: null
+ };
+ ns[n[i]].rows.push(i);
+ }
+
+ for (var i = 0; i < o.length; i++) {
+ if (os[o[i]] == null)
+ os[o[i]] = {
+ rows: new Array(),
+ n: null
+ };
+ os[o[i]].rows.push(i);
+ }
+
+ for (var i in ns) {
+ if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
+ n[ns[i].rows[0]] = {
+ text: n[ns[i].rows[0]],
+ row: os[i].rows[0]
+ };
+ o[os[i].rows[0]] = {
+ text: o[os[i].rows[0]],
+ row: ns[i].rows[0]
+ };
+ }
+ }
+
+ for (var i = 0; i < n.length - 1; i++) {
+ if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
+ n[i + 1] == o[n[i].row + 1]) {
+ n[i + 1] = {
+ text: n[i + 1],
+ row: n[i].row + 1
+ };
+ o[n[i].row + 1] = {
+ text: o[n[i].row + 1],
+ row: i + 1
+ };
+ }
+ }
+
+ for (var i = n.length - 1; i > 0; i--) {
+ if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
+ n[i - 1] == o[n[i].row - 1]) {
+ n[i - 1] = {
+ text: n[i - 1],
+ row: n[i].row - 1
+ };
+ o[n[i].row - 1] = {
+ text: o[n[i].row - 1],
+ row: i - 1
+ };
+ }
+ }
+
+ return {
+ o: o,
+ n: n
+ };
+ }
+
+ return function(o, n){
+ o = o.replace(/\s+$/, '');
+ n = n.replace(/\s+$/, '');
+ var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
+
+ var str = "";
+
+ var oSpace = o.match(/\s+/g);
+ if (oSpace == null) {
+ oSpace = [" "];
+ }
+ else {
+ oSpace.push(" ");
+ }
+ var nSpace = n.match(/\s+/g);
+ if (nSpace == null) {
+ nSpace = [" "];
+ }
+ else {
+ nSpace.push(" ");
+ }
+
+ if (out.n.length == 0) {
+ for (var i = 0; i < out.o.length; i++) {
+ str += '<del>' + out.o[i] + oSpace[i] + "</del>";
+ }
+ }
+ else {
+ if (out.n[0].text == null) {
+ for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
+ str += '<del>' + out.o[n] + oSpace[n] + "</del>";
+ }
+ }
+
+ for (var i = 0; i < out.n.length; i++) {
+ if (out.n[i].text == null) {
+ str += '<ins>' + out.n[i] + nSpace[i] + "</ins>";
+ }
+ else {
+ var pre = "";
+
+ for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
+ pre += '<del>' + out.o[n] + oSpace[n] + "</del>";
+ }
+ str += " " + out.n[i].text + nSpace[i] + pre;
+ }
+ }
+ }
+
+ return str;
+ };
+})();
+
+})(this);
diff --git a/Source/ThirdParty/qunit/test/headless.html b/Source/ThirdParty/qunit/test/headless.html
new file mode 100644
index 000000000..cd1eb7e29
--- /dev/null
+++ b/Source/ThirdParty/qunit/test/headless.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>QUnit Test Suite</title>
+ <link rel="stylesheet" href="../qunit/qunit.css" type="text/css" media="screen">
+ <script type="text/javascript" src="../qunit/qunit.js"></script>
+ <script type="text/javascript" src="test.js"></script>
+ <script type="text/javascript" src="same.js"></script>
+ <script>
+ var logs = ["begin", "testStart", "testDone", "log", "moduleStart", "moduleDone", "done"];
+ for (var i = 0; i < logs.length; i++) {
+ (function() {
+ var log = logs[i];
+ QUnit[log] = function() {
+ console.log(log, arguments);
+ };
+ })();
+ }
+ </script>
+</head>
+<body>
+ <div id="qunit-fixture">test markup</div>
+</body>
+</html>
diff --git a/Source/ThirdParty/qunit/test/index.html b/Source/ThirdParty/qunit/test/index.html
new file mode 100644
index 000000000..64ccfcce6
--- /dev/null
+++ b/Source/ThirdParty/qunit/test/index.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8" />
+ <title>QUnit Test Suite</title>
+ <link rel="stylesheet" href="../qunit/qunit.css" type="text/css" media="screen">
+ <script type="text/javascript" src="../qunit/qunit.js"></script>
+ <script type="text/javascript" src="test.js"></script>
+ <script type="text/javascript" src="same.js"></script>
+</head>
+<body>
+ <h1 id="qunit-header">QUnit Test Suite</h1>
+ <h2 id="qunit-banner"></h2>
+ <div id="qunit-testrunner-toolbar"></div>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests"></ol>
+ <div id="qunit-fixture">test markup</div>
+</body>
+</html>
diff --git a/Source/ThirdParty/qunit/test/logs.html b/Source/ThirdParty/qunit/test/logs.html
new file mode 100644
index 000000000..bd1350746
--- /dev/null
+++ b/Source/ThirdParty/qunit/test/logs.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>QUnit Test Suite</title>
+ <link rel="stylesheet" href="../qunit/qunit.css" type="text/css" media="screen">
+ <script type="text/javascript" src="../qunit/qunit.js"></script>
+ <script type="text/javascript" src="logs.js"></script>
+</head>
+<body>
+ <h1 id="qunit-header">QUnit Test Suite</h1>
+ <h2 id="qunit-banner"></h2>
+ <div id="qunit-testrunner-toolbar"></div>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests"></ol>
+ <div id="qunit-fixture">test markup</div>
+</body>
+</html>
diff --git a/Source/ThirdParty/qunit/test/logs.js b/Source/ThirdParty/qunit/test/logs.js
new file mode 100644
index 000000000..64dc203b6
--- /dev/null
+++ b/Source/ThirdParty/qunit/test/logs.js
@@ -0,0 +1,150 @@
+// TODO disable reordering for this suite!
+
+
+var begin = 0,
+ moduleStart = 0,
+ moduleDone = 0,
+ testStart = 0,
+ testDone = 0,
+ log = 0,
+ moduleContext,
+ moduleDoneContext,
+ testContext,
+ testDoneContext,
+ logContext;
+
+QUnit.begin = function() {
+ begin++;
+};
+QUnit.done = function() {
+};
+QUnit.moduleStart = function(context) {
+ moduleStart++;
+ moduleContext = context;
+};
+QUnit.moduleDone = function(context) {
+ moduleDone++;
+ moduleDoneContext = context;
+};
+QUnit.testStart = function(context) {
+ testStart++;
+ testContext = context;
+};
+QUnit.testDone = function(context) {
+ testDone++;
+ testDoneContext = context;
+};
+QUnit.log = function(context) {
+ log++;
+ logContext = context;
+};
+
+var logs = ["begin", "testStart", "testDone", "log", "moduleStart", "moduleDone", "done"];
+for (var i = 0; i < logs.length; i++) {
+ (function() {
+ var log = logs[i],
+ logger = QUnit[log];
+ QUnit[log] = function() {
+ console.log(log, arguments);
+ logger.apply(this, arguments);
+ };
+ })();
+}
+
+module("logs1");
+
+test("test1", 13, function() {
+ equal(begin, 1);
+ equal(moduleStart, 1);
+ equal(testStart, 1);
+ equal(testDone, 0);
+ equal(moduleDone, 0);
+
+ deepEqual(logContext, {
+ result: true,
+ message: undefined,
+ actual: 0,
+ expected: 0
+ });
+ equal("foo", "foo", "msg");
+ deepEqual(logContext, {
+ result: true,
+ message: "msg",
+ actual: "foo",
+ expected: "foo"
+ });
+ strictEqual(testDoneContext, undefined);
+ deepEqual(testContext, {
+ name: "test1"
+ });
+ strictEqual(moduleDoneContext, undefined);
+ deepEqual(moduleContext, {
+ name: "logs1"
+ });
+
+ equal(log, 12);
+});
+test("test2", 10, function() {
+ equal(begin, 1);
+ equal(moduleStart, 1);
+ equal(testStart, 2);
+ equal(testDone, 1);
+ equal(moduleDone, 0);
+
+ deepEqual(testDoneContext, {
+ name: "test1",
+ failed: 0,
+ passed: 13,
+ total: 13
+ });
+ deepEqual(testContext, {
+ name: "test2"
+ });
+ strictEqual(moduleDoneContext, undefined);
+ deepEqual(moduleContext, {
+ name: "logs1"
+ });
+
+ equal(log, 22);
+});
+
+module("logs2");
+
+test("test1", 9, function() {
+ equal(begin, 1);
+ equal(moduleStart, 2);
+ equal(testStart, 3);
+ equal(testDone, 2);
+ equal(moduleDone, 1);
+
+ deepEqual(testContext, {
+ name: "test1"
+ });
+ deepEqual(moduleDoneContext, {
+ name: "logs1",
+ failed: 0,
+ passed: 23,
+ total: 23
+ });
+ deepEqual(moduleContext, {
+ name: "logs2"
+ });
+
+ equal(log, 31);
+});
+test("test2", 8, function() {
+ equal(begin, 1);
+ equal(moduleStart, 2);
+ equal(testStart, 4);
+ equal(testDone, 3);
+ equal(moduleDone, 1);
+
+ deepEqual(testContext, {
+ name: "test2"
+ });
+ deepEqual(moduleContext, {
+ name: "logs2"
+ });
+
+ equal(log, 39);
+});
diff --git a/Source/ThirdParty/qunit/test/same.js b/Source/ThirdParty/qunit/test/same.js
new file mode 100644
index 000000000..fa7e3eb9a
--- /dev/null
+++ b/Source/ThirdParty/qunit/test/same.js
@@ -0,0 +1,1421 @@
+module("equiv");
+
+
+test("Primitive types and constants", function () {
+ equals(QUnit.equiv(null, null), true, "null");
+ equals(QUnit.equiv(null, {}), false, "null");
+ equals(QUnit.equiv(null, undefined), false, "null");
+ equals(QUnit.equiv(null, 0), false, "null");
+ equals(QUnit.equiv(null, false), false, "null");
+ equals(QUnit.equiv(null, ''), false, "null");
+ equals(QUnit.equiv(null, []), false, "null");
+
+ equals(QUnit.equiv(undefined, undefined), true, "undefined");
+ equals(QUnit.equiv(undefined, null), false, "undefined");
+ equals(QUnit.equiv(undefined, 0), false, "undefined");
+ equals(QUnit.equiv(undefined, false), false, "undefined");
+ equals(QUnit.equiv(undefined, {}), false, "undefined");
+ equals(QUnit.equiv(undefined, []), false, "undefined");
+ equals(QUnit.equiv(undefined, ""), false, "undefined");
+
+ // Nan usually doest not equal to Nan using the '==' operator.
+ // Only isNaN() is able to do it.
+ equals(QUnit.equiv(0/0, 0/0), true, "NaN"); // NaN VS NaN
+ equals(QUnit.equiv(1/0, 2/0), true, "Infinity"); // Infinity VS Infinity
+ equals(QUnit.equiv(-1/0, 2/0), false, "-Infinity, Infinity"); // -Infinity VS Infinity
+ equals(QUnit.equiv(-1/0, -2/0), true, "-Infinity, -Infinity"); // -Infinity VS -Infinity
+ equals(QUnit.equiv(0/0, 1/0), false, "NaN, Infinity"); // Nan VS Infinity
+ equals(QUnit.equiv(1/0, 0/0), false, "NaN, Infinity"); // Nan VS Infinity
+ equals(QUnit.equiv(0/0, null), false, "NaN");
+ equals(QUnit.equiv(0/0, undefined), false, "NaN");
+ equals(QUnit.equiv(0/0, 0), false, "NaN");
+ equals(QUnit.equiv(0/0, false), false, "NaN");
+ equals(QUnit.equiv(0/0, function () {}), false, "NaN");
+ equals(QUnit.equiv(1/0, null), false, "NaN, Infinity");
+ equals(QUnit.equiv(1/0, undefined), false, "NaN, Infinity");
+ equals(QUnit.equiv(1/0, 0), false, "NaN, Infinity");
+ equals(QUnit.equiv(1/0, 1), false, "NaN, Infinity");
+ equals(QUnit.equiv(1/0, false), false, "NaN, Infinity");
+ equals(QUnit.equiv(1/0, true), false, "NaN, Infinity");
+ equals(QUnit.equiv(1/0, function () {}), false, "NaN, Infinity");
+
+ equals(QUnit.equiv(0, 0), true, "number");
+ equals(QUnit.equiv(0, 1), false, "number");
+ equals(QUnit.equiv(1, 0), false, "number");
+ equals(QUnit.equiv(1, 1), true, "number");
+ equals(QUnit.equiv(1.1, 1.1), true, "number");
+ equals(QUnit.equiv(0.0000005, 0.0000005), true, "number");
+ equals(QUnit.equiv(0, ''), false, "number");
+ equals(QUnit.equiv(0, '0'), false, "number");
+ equals(QUnit.equiv(1, '1'), false, "number");
+ equals(QUnit.equiv(0, false), false, "number");
+ equals(QUnit.equiv(1, true), false, "number");
+
+ equals(QUnit.equiv(true, true), true, "boolean");
+ equals(QUnit.equiv(true, false), false, "boolean");
+ equals(QUnit.equiv(false, true), false, "boolean");
+ equals(QUnit.equiv(false, 0), false, "boolean");
+ equals(QUnit.equiv(false, null), false, "boolean");
+ equals(QUnit.equiv(false, undefined), false, "boolean");
+ equals(QUnit.equiv(true, 1), false, "boolean");
+ equals(QUnit.equiv(true, null), false, "boolean");
+ equals(QUnit.equiv(true, undefined), false, "boolean");
+
+ equals(QUnit.equiv('', ''), true, "string");
+ equals(QUnit.equiv('a', 'a'), true, "string");
+ equals(QUnit.equiv("foobar", "foobar"), true, "string");
+ equals(QUnit.equiv("foobar", "foo"), false, "string");
+ equals(QUnit.equiv('', 0), false, "string");
+ equals(QUnit.equiv('', false), false, "string");
+ equals(QUnit.equiv('', null), false, "string");
+ equals(QUnit.equiv('', undefined), false, "string");
+
+ // Short annotation VS new annotation
+ equals(QUnit.equiv(0, new Number()), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Number(), 0), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(1, new Number(1)), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Number(1), 1), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Number(0), 1), false, "short annotation VS new annotation");
+ equals(QUnit.equiv(0, new Number(1)), false, "short annotation VS new annotation");
+
+ equals(QUnit.equiv(new String(), ""), true, "short annotation VS new annotation");
+ equals(QUnit.equiv("", new String()), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(new String("My String"), "My String"), true, "short annotation VS new annotation");
+ equals(QUnit.equiv("My String", new String("My String")), true, "short annotation VS new annotation");
+ equals(QUnit.equiv("Bad String", new String("My String")), false, "short annotation VS new annotation");
+ equals(QUnit.equiv(new String("Bad String"), "My String"), false, "short annotation VS new annotation");
+
+ equals(QUnit.equiv(false, new Boolean()), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Boolean(), false), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(true, new Boolean(true)), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Boolean(true), true), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(true, new Boolean(1)), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(false, new Boolean(false)), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Boolean(false), false), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(false, new Boolean(0)), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(true, new Boolean(false)), false, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Boolean(false), true), false, "short annotation VS new annotation");
+
+ equals(QUnit.equiv(new Object(), {}), true, "short annotation VS new annotation");
+ equals(QUnit.equiv({}, new Object()), true, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Object(), {a:1}), false, "short annotation VS new annotation");
+ equals(QUnit.equiv({a:1}, new Object()), false, "short annotation VS new annotation");
+ equals(QUnit.equiv({a:undefined}, new Object()), false, "short annotation VS new annotation");
+ equals(QUnit.equiv(new Object(), {a:undefined}), false, "short annotation VS new annotation");
+});
+
+test("Objects Basics.", function() {
+ equals(QUnit.equiv({}, {}), true);
+ equals(QUnit.equiv({}, null), false);
+ equals(QUnit.equiv({}, undefined), false);
+ equals(QUnit.equiv({}, 0), false);
+ equals(QUnit.equiv({}, false), false);
+
+ // This test is a hard one, it is very important
+ // REASONS:
+ // 1) They are of the same type "object"
+ // 2) [] instanceof Object is true
+ // 3) Their properties are the same (doesn't exists)
+ equals(QUnit.equiv({}, []), false);
+
+ equals(QUnit.equiv({a:1}, {a:1}), true);
+ equals(QUnit.equiv({a:1}, {a:"1"}), false);
+ equals(QUnit.equiv({a:[]}, {a:[]}), true);
+ equals(QUnit.equiv({a:{}}, {a:null}), false);
+ equals(QUnit.equiv({a:1}, {}), false);
+ equals(QUnit.equiv({}, {a:1}), false);
+
+ // Hard ones
+ equals(QUnit.equiv({a:undefined}, {}), false);
+ equals(QUnit.equiv({}, {a:undefined}), false);
+ equals(QUnit.equiv(
+ {
+ a: [{ bar: undefined }]
+ },
+ {
+ a: [{ bat: undefined }]
+ }
+ ), false);
+});
+
+
+test("Arrays Basics.", function() {
+
+ equals(QUnit.equiv([], []), true);
+
+ // May be a hard one, can invoke a crash at execution.
+ // because their types are both "object" but null isn't
+ // like a true object, it doesn't have any property at all.
+ equals(QUnit.equiv([], null), false);
+
+ equals(QUnit.equiv([], undefined), false);
+ equals(QUnit.equiv([], false), false);
+ equals(QUnit.equiv([], 0), false);
+ equals(QUnit.equiv([], ""), false);
+
+ // May be a hard one, but less hard
+ // than {} with [] (note the order)
+ equals(QUnit.equiv([], {}), false);
+
+ equals(QUnit.equiv([null],[]), false);
+ equals(QUnit.equiv([undefined],[]), false);
+ equals(QUnit.equiv([],[null]), false);
+ equals(QUnit.equiv([],[undefined]), false);
+ equals(QUnit.equiv([null],[undefined]), false);
+ equals(QUnit.equiv([[]],[[]]), true);
+ equals(QUnit.equiv([[],[],[]],[[],[],[]]), true);
+ equals(QUnit.equiv(
+ [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
+ [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]),
+ true);
+ equals(QUnit.equiv(
+ [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
+ [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]), // shorter
+ false);
+ equals(QUnit.equiv(
+ [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[{}]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]],
+ [[],[],[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]), // deepest element not an array
+ false);
+
+ // same multidimensional
+ equals(QUnit.equiv(
+ [1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,[
+ [6,7,8,9, [
+ [
+ 1,2,3,4,[
+ 2,3,4,[
+ 1,2,[
+ 1,2,3,4,[
+ 1,2,3,4,5,6,7,8,9,[
+ 0
+ ],1,2,3,4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],5,6,7
+ ]
+ ]
+ ]
+ ]
+ ]]],
+ [1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,[
+ [6,7,8,9, [
+ [
+ 1,2,3,4,[
+ 2,3,4,[
+ 1,2,[
+ 1,2,3,4,[
+ 1,2,3,4,5,6,7,8,9,[
+ 0
+ ],1,2,3,4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],5,6,7
+ ]
+ ]
+ ]
+ ]
+ ]]]),
+ true, "Multidimensional");
+
+ // different multidimensional
+ equals(QUnit.equiv(
+ [1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,[
+ [6,7,8,9, [
+ [
+ 1,2,3,4,[
+ 2,3,4,[
+ 1,2,[
+ 1,2,3,4,[
+ 1,2,3,4,5,6,7,8,9,[
+ 0
+ ],1,2,3,4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],5,6,7
+ ]
+ ]
+ ]
+ ]
+ ]]],
+ [1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,[
+ [6,7,8,9, [
+ [
+ 1,2,3,4,[
+ 2,3,4,[
+ 1,2,[
+ '1',2,3,4,[ // string instead of number
+ 1,2,3,4,5,6,7,8,9,[
+ 0
+ ],1,2,3,4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],5,6,7
+ ]
+ ]
+ ]
+ ]
+ ]]]),
+ false, "Multidimensional");
+
+ // different multidimensional
+ equals(QUnit.equiv(
+ [1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,[
+ [6,7,8,9, [
+ [
+ 1,2,3,4,[
+ 2,3,4,[
+ 1,2,[
+ 1,2,3,4,[
+ 1,2,3,4,5,6,7,8,9,[
+ 0
+ ],1,2,3,4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],5,6,7
+ ]
+ ]
+ ]
+ ]
+ ]]],
+ [1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,6,7,8,9, [
+ 1,2,3,4,5,[
+ [6,7,8,9, [
+ [
+ 1,2,3,4,[
+ 2,3,[ // missing an element (4)
+ 1,2,[
+ 1,2,3,4,[
+ 1,2,3,4,5,6,7,8,9,[
+ 0
+ ],1,2,3,4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],4,5,6,7,8,9
+ ],5,6,7,8,9
+ ],5,6,7
+ ]
+ ]
+ ]
+ ]
+ ]]]),
+ false, "Multidimensional");
+});
+
+test("Functions.", function() {
+ var f0 = function () {};
+ var f1 = function () {};
+
+ // f2 and f3 have the same code, formatted differently
+ var f2 = function () {var i = 0;};
+ var f3 = function () {
+ var i = 0 // this comment and no semicoma as difference
+ };
+
+ equals(QUnit.equiv(function() {}, function() {}), false, "Anonymous functions"); // exact source code
+ equals(QUnit.equiv(function() {}, function() {return true;}), false, "Anonymous functions");
+
+ equals(QUnit.equiv(f0, f0), true, "Function references"); // same references
+ equals(QUnit.equiv(f0, f1), false, "Function references"); // exact source code, different references
+ equals(QUnit.equiv(f2, f3), false, "Function references"); // equivalent source code, different references
+ equals(QUnit.equiv(f1, f2), false, "Function references"); // different source code, different references
+ equals(QUnit.equiv(function() {}, true), false);
+ equals(QUnit.equiv(function() {}, undefined), false);
+ equals(QUnit.equiv(function() {}, null), false);
+ equals(QUnit.equiv(function() {}, {}), false);
+});
+
+
+test("Date instances.", function() {
+ // Date, we don't need to test Date.parse() because it returns a number.
+ // Only test the Date instances by setting them a fix date.
+ // The date use is midnight January 1, 1970
+
+ var d1 = new Date();
+ d1.setTime(0); // fix the date
+
+ var d2 = new Date();
+ d2.setTime(0); // fix the date
+
+ var d3 = new Date(); // The very now
+
+ // Anyway their types differs, just in case the code fails in the order in which it deals with date
+ equals(QUnit.equiv(d1, 0), false); // d1.valueOf() returns 0, but d1 and 0 are different
+ // test same values date and different instances equality
+ equals(QUnit.equiv(d1, d2), true);
+ // test different date and different instances difference
+ equals(QUnit.equiv(d1, d3), false);
+});
+
+
+test("RegExp.", function() {
+ // Must test cases that imply those traps:
+ // var a = /./;
+ // a instanceof Object; // Oops
+ // a instanceof RegExp; // Oops
+ // typeof a === "function"; // Oops, false in IE and Opera, true in FF and Safari ("object")
+
+ // Tests same regex with same modifiers in different order
+ var r = /foo/;
+ var r5 = /foo/gim;
+ var r6 = /foo/gmi;
+ var r7 = /foo/igm;
+ var r8 = /foo/img;
+ var r9 = /foo/mig;
+ var r10 = /foo/mgi;
+ var ri1 = /foo/i;
+ var ri2 = /foo/i;
+ var rm1 = /foo/m;
+ var rm2 = /foo/m;
+ var rg1 = /foo/g;
+ var rg2 = /foo/g;
+
+ equals(QUnit.equiv(r5, r6), true, "Modifier order");
+ equals(QUnit.equiv(r5, r7), true, "Modifier order");
+ equals(QUnit.equiv(r5, r8), true, "Modifier order");
+ equals(QUnit.equiv(r5, r9), true, "Modifier order");
+ equals(QUnit.equiv(r5, r10), true, "Modifier order");
+ equals(QUnit.equiv(r, r5), false, "Modifier");
+
+ equals(QUnit.equiv(ri1, ri2), true, "Modifier");
+ equals(QUnit.equiv(r, ri1), false, "Modifier");
+ equals(QUnit.equiv(ri1, rm1), false, "Modifier");
+ equals(QUnit.equiv(r, rm1), false, "Modifier");
+ equals(QUnit.equiv(rm1, ri1), false, "Modifier");
+ equals(QUnit.equiv(rm1, rm2), true, "Modifier");
+ equals(QUnit.equiv(rg1, rm1), false, "Modifier");
+ equals(QUnit.equiv(rm1, rg1), false, "Modifier");
+ equals(QUnit.equiv(rg1, rg2), true, "Modifier");
+
+ // Different regex, same modifiers
+ var r11 = /[a-z]/gi;
+ var r13 = /[0-9]/gi; // oops! different
+ equals(QUnit.equiv(r11, r13), false, "Regex pattern");
+
+ var r14 = /0/ig;
+ var r15 = /"0"/ig; // oops! different
+ equals(QUnit.equiv(r14, r15), false, "Regex pattern");
+
+ var r1 = /[\n\r\u2028\u2029]/g;
+ var r2 = /[\n\r\u2028\u2029]/g;
+ var r3 = /[\n\r\u2028\u2028]/g; // differs from r1
+ var r4 = /[\n\r\u2028\u2029]/; // differs from r1
+
+ equals(QUnit.equiv(r1, r2), true, "Regex pattern");
+ equals(QUnit.equiv(r1, r3), false, "Regex pattern");
+ equals(QUnit.equiv(r1, r4), false, "Regex pattern");
+
+ // More complex regex
+ var regex1 = "^[-_.a-z0-9]+@([-_a-z0-9]+\\.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
+ var regex2 = "^[-_.a-z0-9]+@([-_a-z0-9]+\\.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
+ // regex 3 is different: '.' not escaped
+ var regex3 = "^[-_.a-z0-9]+@([-_a-z0-9]+.)+([A-Za-z][A-Za-z]|[A-Za-z][A-Za-z][A-Za-z])|(([0-9][0-9]?|[0-1][0-9][0-9]|[2][0-4][0-9]|[2][5][0-5]))$";
+
+ var r21 = new RegExp(regex1);
+ var r22 = new RegExp(regex2);
+ var r23 = new RegExp(regex3); // diff from r21, not same pattern
+ var r23a = new RegExp(regex3, "gi"); // diff from r23, not same modifier
+ var r24a = new RegExp(regex3, "ig"); // same as r23a
+
+ equals(QUnit.equiv(r21, r22), true, "Complex Regex");
+ equals(QUnit.equiv(r21, r23), false, "Complex Regex");
+ equals(QUnit.equiv(r23, r23a), false, "Complex Regex");
+ equals(QUnit.equiv(r23a, r24a), true, "Complex Regex");
+
+ // typeof r1 is "function" in some browsers and "object" in others so we must cover this test
+ var re = / /;
+ equals(QUnit.equiv(re, function () {}), false, "Regex internal");
+ equals(QUnit.equiv(re, {}), false, "Regex internal");
+});
+
+
+test("Complex Objects.", function() {
+
+ function fn1() {
+ return "fn1";
+ }
+ function fn2() {
+ return "fn2";
+ }
+
+ // Try to invert the order of some properties to make sure it is covered.
+ // It can failed when properties are compared between unsorted arrays.
+ equals(QUnit.equiv(
+ {
+ a: 1,
+ b: null,
+ c: [{}],
+ d: {
+ a: 3.14159,
+ b: false,
+ c: {
+ e: fn1,
+ f: [[[]]],
+ g: {
+ j: {
+ k: {
+ n: {
+ r: "r",
+ s: [1,2,3],
+ t: undefined,
+ u: 0,
+ v: {
+ w: {
+ x: {
+ y: "Yahoo!",
+ z: null
+ }
+ }
+ }
+ },
+ q: [],
+ p: 1/0,
+ o: 99
+ },
+ l: undefined,
+ m: null
+ }
+ },
+ d: 0,
+ i: true,
+ h: "false"
+ }
+ },
+ e: undefined,
+ g: "",
+ h: "h",
+ f: {},
+ i: []
+ },
+ {
+ a: 1,
+ b: null,
+ c: [{}],
+ d: {
+ b: false,
+ a: 3.14159,
+ c: {
+ d: 0,
+ e: fn1,
+ f: [[[]]],
+ g: {
+ j: {
+ k: {
+ n: {
+ r: "r",
+ t: undefined,
+ u: 0,
+ s: [1,2,3],
+ v: {
+ w: {
+ x: {
+ z: null,
+ y: "Yahoo!"
+ }
+ }
+ }
+ },
+ o: 99,
+ p: 1/0,
+ q: []
+ },
+ l: undefined,
+ m: null
+ }
+ },
+ i: true,
+ h: "false"
+ }
+ },
+ e: undefined,
+ g: "",
+ f: {},
+ h: "h",
+ i: []
+ }
+ ), true);
+
+ equals(QUnit.equiv(
+ {
+ a: 1,
+ b: null,
+ c: [{}],
+ d: {
+ a: 3.14159,
+ b: false,
+ c: {
+ d: 0,
+ e: fn1,
+ f: [[[]]],
+ g: {
+ j: {
+ k: {
+ n: {
+ //r: "r", // different: missing a property
+ s: [1,2,3],
+ t: undefined,
+ u: 0,
+ v: {
+ w: {
+ x: {
+ y: "Yahoo!",
+ z: null
+ }
+ }
+ }
+ },
+ o: 99,
+ p: 1/0,
+ q: []
+ },
+ l: undefined,
+ m: null
+ }
+ },
+ h: "false",
+ i: true
+ }
+ },
+ e: undefined,
+ f: {},
+ g: "",
+ h: "h",
+ i: []
+ },
+ {
+ a: 1,
+ b: null,
+ c: [{}],
+ d: {
+ a: 3.14159,
+ b: false,
+ c: {
+ d: 0,
+ e: fn1,
+ f: [[[]]],
+ g: {
+ j: {
+ k: {
+ n: {
+ r: "r",
+ s: [1,2,3],
+ t: undefined,
+ u: 0,
+ v: {
+ w: {
+ x: {
+ y: "Yahoo!",
+ z: null
+ }
+ }
+ }
+ },
+ o: 99,
+ p: 1/0,
+ q: []
+ },
+ l: undefined,
+ m: null
+ }
+ },
+ h: "false",
+ i: true
+ }
+ },
+ e: undefined,
+ f: {},
+ g: "",
+ h: "h",
+ i: []
+ }
+ ), false);
+
+ equals(QUnit.equiv(
+ {
+ a: 1,
+ b: null,
+ c: [{}],
+ d: {
+ a: 3.14159,
+ b: false,
+ c: {
+ d: 0,
+ e: fn1,
+ f: [[[]]],
+ g: {
+ j: {
+ k: {
+ n: {
+ r: "r",
+ s: [1,2,3],
+ t: undefined,
+ u: 0,
+ v: {
+ w: {
+ x: {
+ y: "Yahoo!",
+ z: null
+ }
+ }
+ }
+ },
+ o: 99,
+ p: 1/0,
+ q: []
+ },
+ l: undefined,
+ m: null
+ }
+ },
+ h: "false",
+ i: true
+ }
+ },
+ e: undefined,
+ f: {},
+ g: "",
+ h: "h",
+ i: []
+ },
+ {
+ a: 1,
+ b: null,
+ c: [{}],
+ d: {
+ a: 3.14159,
+ b: false,
+ c: {
+ d: 0,
+ e: fn1,
+ f: [[[]]],
+ g: {
+ j: {
+ k: {
+ n: {
+ r: "r",
+ s: [1,2,3],
+ //t: undefined, // different: missing a property with an undefined value
+ u: 0,
+ v: {
+ w: {
+ x: {
+ y: "Yahoo!",
+ z: null
+ }
+ }
+ }
+ },
+ o: 99,
+ p: 1/0,
+ q: []
+ },
+ l: undefined,
+ m: null
+ }
+ },
+ h: "false",
+ i: true
+ }
+ },
+ e: undefined,
+ f: {},
+ g: "",
+ h: "h",
+ i: []
+ }
+ ), false);
+
+ equals(QUnit.equiv(
+ {
+ a: 1,
+ b: null,
+ c: [{}],
+ d: {
+ a: 3.14159,
+ b: false,
+ c: {
+ d: 0,
+ e: fn1,
+ f: [[[]]],
+ g: {
+ j: {
+ k: {
+ n: {
+ r: "r",
+ s: [1,2,3],
+ t: undefined,
+ u: 0,
+ v: {
+ w: {
+ x: {
+ y: "Yahoo!",
+ z: null
+ }
+ }
+ }
+ },
+ o: 99,
+ p: 1/0,
+ q: []
+ },
+ l: undefined,
+ m: null
+ }
+ },
+ h: "false",
+ i: true
+ }
+ },
+ e: undefined,
+ f: {},
+ g: "",
+ h: "h",
+ i: []
+ },
+ {
+ a: 1,
+ b: null,
+ c: [{}],
+ d: {
+ a: 3.14159,
+ b: false,
+ c: {
+ d: 0,
+ e: fn1,
+ f: [[[]]],
+ g: {
+ j: {
+ k: {
+ n: {
+ r: "r",
+ s: [1,2,3],
+ t: undefined,
+ u: 0,
+ v: {
+ w: {
+ x: {
+ y: "Yahoo!",
+ z: null
+ }
+ }
+ }
+ },
+ o: 99,
+ p: 1/0,
+ q: {} // different was []
+ },
+ l: undefined,
+ m: null
+ }
+ },
+ h: "false",
+ i: true
+ }
+ },
+ e: undefined,
+ f: {},
+ g: "",
+ h: "h",
+ i: []
+ }
+ ), false);
+
+ var same1 = {
+ a: [
+ "string", null, 0, "1", 1, {
+ prop: null,
+ foo: [1,2,null,{}, [], [1,2,3]],
+ bar: undefined
+ }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+ ],
+ unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+ b: "b",
+ c: fn1
+ };
+
+ var same2 = {
+ a: [
+ "string", null, 0, "1", 1, {
+ prop: null,
+ foo: [1,2,null,{}, [], [1,2,3]],
+ bar: undefined
+ }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+ ],
+ unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+ b: "b",
+ c: fn1
+ };
+
+ var diff1 = {
+ a: [
+ "string", null, 0, "1", 1, {
+ prop: null,
+ foo: [1,2,null,{}, [], [1,2,3,4]], // different: 4 was add to the array
+ bar: undefined
+ }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+ ],
+ unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+ b: "b",
+ c: fn1
+ };
+
+ var diff2 = {
+ a: [
+ "string", null, 0, "1", 1, {
+ prop: null,
+ foo: [1,2,null,{}, [], [1,2,3]],
+ newprop: undefined, // different: newprop was added
+ bar: undefined
+ }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+ ],
+ unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+ b: "b",
+ c: fn1
+ };
+
+ var diff3 = {
+ a: [
+ "string", null, 0, "1", 1, {
+ prop: null,
+ foo: [1,2,null,{}, [], [1,2,3]],
+ bar: undefined
+ }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ α" // different: missing last char
+ ],
+ unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+ b: "b",
+ c: fn1
+ };
+
+ var diff4 = {
+ a: [
+ "string", null, 0, "1", 1, {
+ prop: null,
+ foo: [1,2,undefined,{}, [], [1,2,3]], // different: undefined instead of null
+ bar: undefined
+ }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+ ],
+ unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+ b: "b",
+ c: fn1
+ };
+
+ var diff5 = {
+ a: [
+ "string", null, 0, "1", 1, {
+ prop: null,
+ foo: [1,2,null,{}, [], [1,2,3]],
+ bat: undefined // different: property name not "bar"
+ }, 3, "Hey!", "Κάνε πάντα γνωρίζουμε ας των, μηχανής επιδιόρθωσης επιδιορθώσεις ώς μια. Κλπ ας"
+ ],
+ unicode: "老 汉语中存在 港澳和海外的华人圈中 贵州 我去了书店 现在尚有争",
+ b: "b",
+ c: fn1
+ };
+
+ equals(QUnit.equiv(same1, same2), true);
+ equals(QUnit.equiv(same2, same1), true);
+ equals(QUnit.equiv(same2, diff1), false);
+ equals(QUnit.equiv(diff1, same2), false);
+
+ equals(QUnit.equiv(same1, diff1), false);
+ equals(QUnit.equiv(same1, diff2), false);
+ equals(QUnit.equiv(same1, diff3), false);
+ equals(QUnit.equiv(same1, diff3), false);
+ equals(QUnit.equiv(same1, diff4), false);
+ equals(QUnit.equiv(same1, diff5), false);
+ equals(QUnit.equiv(diff5, diff1), false);
+});
+
+
+test("Complex Arrays.", function() {
+
+ function fn() {
+ }
+
+ equals(QUnit.equiv(
+ [1, 2, 3, true, {}, null, [
+ {
+ a: ["", '1', 0]
+ },
+ 5, 6, 7
+ ], "foo"],
+ [1, 2, 3, true, {}, null, [
+ {
+ a: ["", '1', 0]
+ },
+ 5, 6, 7
+ ], "foo"]),
+ true);
+
+ equals(QUnit.equiv(
+ [1, 2, 3, true, {}, null, [
+ {
+ a: ["", '1', 0]
+ },
+ 5, 6, 7
+ ], "foo"],
+ [1, 2, 3, true, {}, null, [
+ {
+ b: ["", '1', 0] // not same property name
+ },
+ 5, 6, 7
+ ], "foo"]),
+ false);
+
+ var a = [{
+ b: fn,
+ c: false,
+ "do": "reserved word",
+ "for": {
+ ar: [3,5,9,"hey!", [], {
+ ar: [1,[
+ 3,4,6,9, null, [], []
+ ]],
+ e: fn,
+ f: undefined
+ }]
+ },
+ e: 0.43445
+ }, 5, "string", 0, fn, false, null, undefined, 0, [
+ 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+ ], [], [[[], "foo", null, {
+ n: 1/0,
+ z: {
+ a: [3,4,5,6,"yep!", undefined, undefined],
+ b: {}
+ }
+ }, {}]]];
+
+ equals(QUnit.equiv(a,
+ [{
+ b: fn,
+ c: false,
+ "do": "reserved word",
+ "for": {
+ ar: [3,5,9,"hey!", [], {
+ ar: [1,[
+ 3,4,6,9, null, [], []
+ ]],
+ e: fn,
+ f: undefined
+ }]
+ },
+ e: 0.43445
+ }, 5, "string", 0, fn, false, null, undefined, 0, [
+ 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+ ], [], [[[], "foo", null, {
+ n: 1/0,
+ z: {
+ a: [3,4,5,6,"yep!", undefined, undefined],
+ b: {}
+ }
+ }, {}]]]), true);
+
+ equals(QUnit.equiv(a,
+ [{
+ b: fn,
+ c: false,
+ "do": "reserved word",
+ "for": {
+ ar: [3,5,9,"hey!", [], {
+ ar: [1,[
+ 3,4,6,9, null, [], []
+ ]],
+ e: fn,
+ f: undefined
+ }]
+ },
+ e: 0.43445
+ }, 5, "string", 0, fn, false, null, undefined, 0, [
+ 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[2]]]], "3"], {}, 1/0 // different: [[[[[2]]]]] instead of [[[[[3]]]]]
+ ], [], [[[], "foo", null, {
+ n: 1/0,
+ z: {
+ a: [3,4,5,6,"yep!", undefined, undefined],
+ b: {}
+ }
+ }, {}]]]), false);
+
+ equals(QUnit.equiv(a,
+ [{
+ b: fn,
+ c: false,
+ "do": "reserved word",
+ "for": {
+ ar: [3,5,9,"hey!", [], {
+ ar: [1,[
+ 3,4,6,9, null, [], []
+ ]],
+ e: fn,
+ f: undefined
+ }]
+ },
+ e: 0.43445
+ }, 5, "string", 0, fn, false, null, undefined, 0, [
+ 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+ ], [], [[[], "foo", null, {
+ n: -1/0, // different, -Infinity instead of Infinity
+ z: {
+ a: [3,4,5,6,"yep!", undefined, undefined],
+ b: {}
+ }
+ }, {}]]]), false);
+
+ equals(QUnit.equiv(a,
+ [{
+ b: fn,
+ c: false,
+ "do": "reserved word",
+ "for": {
+ ar: [3,5,9,"hey!", [], {
+ ar: [1,[
+ 3,4,6,9, null, [], []
+ ]],
+ e: fn,
+ f: undefined
+ }]
+ },
+ e: 0.43445
+ }, 5, "string", 0, fn, false, null, undefined, 0, [
+ 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+ ], [], [[[], "foo", { // different: null is missing
+ n: 1/0,
+ z: {
+ a: [3,4,5,6,"yep!", undefined, undefined],
+ b: {}
+ }
+ }, {}]]]), false);
+
+ equals(QUnit.equiv(a,
+ [{
+ b: fn,
+ c: false,
+ "do": "reserved word",
+ "for": {
+ ar: [3,5,9,"hey!", [], {
+ ar: [1,[
+ 3,4,6,9, null, [], []
+ ]],
+ e: fn
+ // different: missing property f: undefined
+ }]
+ },
+ e: 0.43445
+ }, 5, "string", 0, fn, false, null, undefined, 0, [
+ 4,5,6,7,8,9,11,22,33,44,55,"66", null, [], [[[[[3]]]], "3"], {}, 1/0
+ ], [], [[[], "foo", null, {
+ n: 1/0,
+ z: {
+ a: [3,4,5,6,"yep!", undefined, undefined],
+ b: {}
+ }
+ }, {}]]]), false);
+});
+
+
+test("Prototypal inheritance", function() {
+ function Gizmo(id) {
+ this.id = id;
+ }
+
+ function Hoozit(id) {
+ this.id = id;
+ }
+ Hoozit.prototype = new Gizmo();
+
+ var gizmo = new Gizmo("ok");
+ var hoozit = new Hoozit("ok");
+
+ // Try this test many times after test on instances that hold function
+ // to make sure that our code does not mess with last object constructor memoization.
+ equals(QUnit.equiv(function () {}, function () {}), false);
+
+ // Hoozit inherit from Gizmo
+ // hoozit instanceof Hoozit; // true
+ // hoozit instanceof Gizmo; // true
+ equals(QUnit.equiv(hoozit, gizmo), true);
+
+ Gizmo.prototype.bar = true; // not a function just in case we skip them
+
+ // Hoozit inherit from Gizmo
+ // They are equivalent
+ equals(QUnit.equiv(hoozit, gizmo), true);
+
+ // Make sure this is still true !important
+ // The reason for this is that I forgot to reset the last
+ // caller to where it were called from.
+ equals(QUnit.equiv(function () {}, function () {}), false);
+
+ // Make sure this is still true !important
+ equals(QUnit.equiv(hoozit, gizmo), true);
+
+ Hoozit.prototype.foo = true; // not a function just in case we skip them
+
+ // Gizmo does not inherit from Hoozit
+ // gizmo instanceof Gizmo; // true
+ // gizmo instanceof Hoozit; // false
+ // They are not equivalent
+ equals(QUnit.equiv(hoozit, gizmo), false);
+
+ // Make sure this is still true !important
+ equals(QUnit.equiv(function () {}, function () {}), false);
+});
+
+
+test("Instances", function() {
+ function A() {}
+ var a1 = new A();
+ var a2 = new A();
+
+ function B() {
+ this.fn = function () {};
+ }
+ var b1 = new B();
+ var b2 = new B();
+
+ equals(QUnit.equiv(a1, a2), true, "Same property, same constructor");
+
+ // b1.fn and b2.fn are functions but they are different references
+ // But we decided to skip function for instances.
+ equals(QUnit.equiv(b1, b2), true, "Same property, same constructor");
+ equals(QUnit.equiv(a1, b1), false, "Same properties but different constructor"); // failed
+
+ function Car(year) {
+ var privateVar = 0;
+ this.year = year;
+ this.isOld = function() {
+ return year > 10;
+ };
+ }
+
+ function Human(year) {
+ var privateVar = 1;
+ this.year = year;
+ this.isOld = function() {
+ return year > 80;
+ };
+ }
+
+ var car = new Car(30);
+ var carSame = new Car(30);
+ var carDiff = new Car(10);
+ var human = new Human(30);
+
+ var diff = {
+ year: 30
+ };
+
+ var same = {
+ year: 30,
+ isOld: function () {}
+ };
+
+ equals(QUnit.equiv(car, car), true);
+ equals(QUnit.equiv(car, carDiff), false);
+ equals(QUnit.equiv(car, carSame), true);
+ equals(QUnit.equiv(car, human), false);
+});
+
+
+test("Complex Instances Nesting (with function value in literals and/or in nested instances)", function() {
+ function A(fn) {
+ this.a = {};
+ this.fn = fn;
+ this.b = {a: []};
+ this.o = {};
+ this.fn1 = fn;
+ }
+ function B(fn) {
+ this.fn = fn;
+ this.fn1 = function () {};
+ this.a = new A(function () {});
+ }
+
+ function fnOutside() {
+ }
+
+ function C(fn) {
+ function fnInside() {
+ }
+ this.x = 10;
+ this.fn = fn;
+ this.fn1 = function () {};
+ this.fn2 = fnInside;
+ this.fn3 = {
+ a: true,
+ b: fnOutside // ok make reference to a function in all instances scope
+ };
+ this.o1 = {};
+
+ // This function will be ignored.
+ // Even if it is not visible for all instances (e.g. locked in a closures),
+ // it is from a property that makes part of an instance (e.g. from the C constructor)
+ this.b1 = new B(function () {});
+ this.b2 = new B({
+ x: {
+ b2: new B(function() {})
+ }
+ });
+ }
+
+ function D(fn) {
+ function fnInside() {
+ }
+ this.x = 10;
+ this.fn = fn;
+ this.fn1 = function () {};
+ this.fn2 = fnInside;
+ this.fn3 = {
+ a: true,
+ b: fnOutside, // ok make reference to a function in all instances scope
+
+ // This function won't be ingored.
+ // It isn't visible for all C insances
+ // and it is not in a property of an instance. (in an Object instances e.g. the object literal)
+ c: fnInside
+ };
+ this.o1 = {};
+
+ // This function will be ignored.
+ // Even if it is not visible for all instances (e.g. locked in a closures),
+ // it is from a property that makes part of an instance (e.g. from the C constructor)
+ this.b1 = new B(function () {});
+ this.b2 = new B({
+ x: {
+ b2: new B(function() {})
+ }
+ });
+ }
+
+ function E(fn) {
+ function fnInside() {
+ }
+ this.x = 10;
+ this.fn = fn;
+ this.fn1 = function () {};
+ this.fn2 = fnInside;
+ this.fn3 = {
+ a: true,
+ b: fnOutside // ok make reference to a function in all instances scope
+ };
+ this.o1 = {};
+
+ // This function will be ignored.
+ // Even if it is not visible for all instances (e.g. locked in a closures),
+ // it is from a property that makes part of an instance (e.g. from the C constructor)
+ this.b1 = new B(function () {});
+ this.b2 = new B({
+ x: {
+ b1: new B({a: function() {}}),
+ b2: new B(function() {})
+ }
+ });
+ }
+
+
+ var a1 = new A(function () {});
+ var a2 = new A(function () {});
+ equals(QUnit.equiv(a1, a2), true);
+
+ equals(QUnit.equiv(a1, a2), true); // different instances
+
+ var b1 = new B(function () {});
+ var b2 = new B(function () {});
+ equals(QUnit.equiv(b1, b2), true);
+
+ var c1 = new C(function () {});
+ var c2 = new C(function () {});
+ equals(QUnit.equiv(c1, c2), true);
+
+ var d1 = new D(function () {});
+ var d2 = new D(function () {});
+ equals(QUnit.equiv(d1, d2), false);
+
+ var e1 = new E(function () {});
+ var e2 = new E(function () {});
+ equals(QUnit.equiv(e1, e2), false);
+
+});
+
+
+test('object with references to self wont loop', function(){
+ var circularA = {
+ abc:null
+ }, circularB = {
+ abc:null
+ };
+ circularA.abc = circularA;
+ circularB.abc = circularB;
+ equals(QUnit.equiv(circularA, circularB), true, "Should not repeat test on object (ambigous test)");
+
+ circularA.def = 1;
+ circularB.def = 1;
+ equals(QUnit.equiv(circularA, circularB), true, "Should not repeat test on object (ambigous test)");
+
+ circularA.def = 1;
+ circularB.def = 0;
+ equals(QUnit.equiv(circularA, circularB), false, "Should not repeat test on object (unambigous test)");
+});
+
+test('array with references to self wont loop', function(){
+ var circularA = [],
+ circularB = [];
+ circularA.push(circularA);
+ circularB.push(circularB);
+ equals(QUnit.equiv(circularA, circularB), true, "Should not repeat test on array (ambigous test)");
+
+ circularA.push( 'abc' );
+ circularB.push( 'abc' );
+ equals(QUnit.equiv(circularA, circularB), true, "Should not repeat test on array (ambigous test)");
+
+ circularA.push( 'hello' );
+ circularB.push( 'goodbye' );
+ equals(QUnit.equiv(circularA, circularB), false, "Should not repeat test on array (unambigous test)");
+});
+
+test('mixed object/array with references to self wont loop', function(){
+ var circularA = [{abc:null}],
+ circularB = [{abc:null}];
+ circularA[0].abc = circularA;
+ circularB[0].abc = circularB;
+
+ circularA.push(circularA);
+ circularB.push(circularB);
+ equals(QUnit.equiv(circularA, circularB), true, "Should not repeat test on object/array (ambigous test)");
+
+ circularA[0].def = 1;
+ circularB[0].def = 1;
+ equals(QUnit.equiv(circularA, circularB), true, "Should not repeat test on object/array (ambigous test)");
+
+ circularA[0].def = 1;
+ circularB[0].def = 0;
+ equals(QUnit.equiv(circularA, circularB), false, "Should not repeat test on object/array (unambigous test)");
+});
+
+test("Test that must be done at the end because they extend some primitive's prototype", function() {
+ // Try that a function looks like our regular expression.
+ // This tests if we check that a and b are really both instance of RegExp
+ Function.prototype.global = true;
+ Function.prototype.multiline = true;
+ Function.prototype.ignoreCase = false;
+ Function.prototype.source = "my regex";
+ var re = /my regex/gm;
+ equals(QUnit.equiv(re, function () {}), false, "A function that looks that a regex isn't a regex");
+ // This test will ensures it works in both ways, and ALSO especially that we can make differences
+ // between RegExp and Function constructor because typeof on a RegExpt instance is "function"
+ equals(QUnit.equiv(function () {}, re), false, "Same conversely, but ensures that function and regexp are distinct because their constructor are different");
+});
diff --git a/Source/ThirdParty/qunit/test/test.js b/Source/ThirdParty/qunit/test/test.js
new file mode 100644
index 000000000..3f942d2dd
--- /dev/null
+++ b/Source/ThirdParty/qunit/test/test.js
@@ -0,0 +1,324 @@
+test("module without setup/teardown (default)", function() {
+ expect(1);
+ ok(true);
+});
+
+test("expect in test", 3, function() {
+ ok(true);
+ ok(true);
+ ok(true);
+});
+
+test("expect in test", 1, function() {
+ ok(true);
+});
+
+module("setup test", {
+ setup: function() {
+ ok(true);
+ }
+});
+
+test("module with setup", function() {
+ expect(2);
+ ok(true);
+});
+
+test("module with setup, expect in test call", 2, function() {
+ ok(true);
+});
+
+var state;
+
+module("setup/teardown test", {
+ setup: function() {
+ state = true;
+ ok(true);
+ },
+ teardown: function() {
+ ok(true);
+ }
+});
+
+test("module with setup/teardown", function() {
+ expect(3);
+ ok(true);
+});
+
+module("setup/teardown test 2");
+
+test("module without setup/teardown", function() {
+ expect(1);
+ ok(true);
+});
+
+if (typeof setTimeout !== 'undefined') {
+state = 'fail';
+
+module("teardown and stop", {
+ teardown: function() {
+ equal(state, "done", "Test teardown.");
+ }
+});
+
+test("teardown must be called after test ended", function() {
+ expect(1);
+ stop();
+ setTimeout(function() {
+ state = "done";
+ start();
+ }, 13);
+});
+
+module("async setup test", {
+ setup: function() {
+ stop();
+ setTimeout(function(){
+ ok(true);
+ start();
+ }, 500);
+ }
+});
+
+asyncTest("module with async setup", function() {
+ expect(2);
+ ok(true);
+ start();
+});
+
+module("async teardown test", {
+ teardown: function() {
+ stop();
+ setTimeout(function(){
+ ok(true);
+ start();
+ }, 500);
+ }
+});
+
+asyncTest("module with async teardown", function() {
+ expect(2);
+ ok(true);
+ start();
+});
+
+module("asyncTest");
+
+asyncTest("asyncTest", function() {
+ expect(2);
+ ok(true);
+ setTimeout(function() {
+ state = "done";
+ ok(true);
+ start();
+ }, 13);
+});
+
+asyncTest("asyncTest", 2, function() {
+ ok(true);
+ setTimeout(function() {
+ state = "done";
+ ok(true);
+ start();
+ }, 13);
+});
+
+test("sync", 2, function() {
+ stop();
+ setTimeout(function() {
+ ok(true);
+ start();
+ }, 13);
+ stop();
+ setTimeout(function() {
+ ok(true);
+ start();
+ }, 125);
+});
+}
+
+module("save scope", {
+ setup: function() {
+ this.foo = "bar";
+ },
+ teardown: function() {
+ deepEqual(this.foo, "bar");
+ }
+});
+test("scope check", function() {
+ expect(2);
+ deepEqual(this.foo, "bar");
+});
+
+module("simple testEnvironment setup", {
+ foo: "bar",
+ bugid: "#5311" // example of meta-data
+});
+test("scope check", function() {
+ deepEqual(this.foo, "bar");
+});
+test("modify testEnvironment",function() {
+ this.foo="hamster";
+});
+test("testEnvironment reset for next test",function() {
+ deepEqual(this.foo, "bar");
+});
+
+module("testEnvironment with object", {
+ options:{
+ recipe:"soup",
+ ingredients:["hamster","onions"]
+ }
+});
+test("scope check", function() {
+ deepEqual(this.options, {recipe:"soup",ingredients:["hamster","onions"]}) ;
+});
+test("modify testEnvironment",function() {
+ // since we do a shallow copy, the testEnvironment can be modified
+ this.options.ingredients.push("carrots");
+});
+test("testEnvironment reset for next test",function() {
+ deepEqual(this.options, {recipe:"soup",ingredients:["hamster","onions","carrots"]}, "Is this a bug or a feature? Could do a deep copy") ;
+});
+
+
+module("testEnvironment tests");
+
+function makeurl() {
+ var testEnv = QUnit.current_testEnvironment;
+ var url = testEnv.url || 'http://example.com/search';
+ var q = testEnv.q || 'a search test';
+ return url + '?q='+encodeURIComponent(q);
+}
+
+test("makeurl working",function() {
+ equal( QUnit.current_testEnvironment, this, 'The current testEnvironment is global');
+ equal( makeurl(), 'http://example.com/search?q=a%20search%20test', 'makeurl returns a default url if nothing specified in the testEnvironment');
+});
+
+module("testEnvironment with makeurl settings", {
+ url: 'http://google.com/',
+ q: 'another_search_test'
+});
+test("makeurl working with settings from testEnvironment", function() {
+ equal( makeurl(), 'http://google.com/?q=another_search_test', 'rather than passing arguments, we use test metadata to form the url');
+});
+test("each test can extend the module testEnvironment", {
+ q:'hamstersoup'
+}, function() {
+ equal( makeurl(), 'http://google.com/?q=hamstersoup', 'url from module, q from test');
+});
+
+module("jsDump");
+test("jsDump output", function() {
+ equals( QUnit.jsDump.parse([1, 2]), "[\n 1,\n 2\n]" );
+ equals( QUnit.jsDump.parse({top: 5, left: 0}), "{\n \"top\": 5,\n \"left\": 0\n}" );
+ if (typeof document !== 'undefined' && document.getElementById("qunit-header")) {
+ equals( QUnit.jsDump.parse(document.getElementById("qunit-header")), "<h1 id=\"qunit-header\"></h1>" );
+ equals( QUnit.jsDump.parse(document.getElementsByTagName("h1")), "[\n <h1 id=\"qunit-header\"></h1>\n]" );
+ }
+});
+
+module("assertions");
+test("raises",function() {
+ function CustomError( message ) {
+ this.message = message;
+ }
+
+ CustomError.prototype.toString = function() {
+ return this.message;
+ };
+
+ raises(
+ function() {
+ throw "error"
+ }
+ );
+
+ raises(
+ function() {
+ throw "error"
+ },
+ 'raises with just a message, no expected'
+ );
+
+ raises(
+ function() {
+ throw new CustomError();
+ },
+ CustomError,
+ 'raised error is an instance of CustomError'
+ );
+
+ raises(
+ function() {
+ throw new CustomError("some error description");
+ },
+ /description/,
+ "raised error message contains 'description'"
+ );
+
+ raises(
+ function() {
+ throw new CustomError("some error description");
+ },
+ function( err ) {
+ if ( (err instanceof CustomError) && /description/.test(err) ) {
+ return true;
+ }
+ },
+ "custom validation function"
+ );
+
+});
+
+if (typeof document !== "undefined") {
+
+module("fixture");
+test("setup", function() {
+ document.getElementById("qunit-fixture").innerHTML = "foobar";
+});
+test("basics", function() {
+ equal( document.getElementById("qunit-fixture").innerHTML, "test markup", "automatically reset" );
+});
+
+}
+
+module("custom assertions");
+(function() {
+ function mod2(value, expected, message) {
+ var actual = value % 2;
+ QUnit.push(actual == expected, actual, expected, message);
+ }
+ test("mod2", function() {
+ mod2(2, 0, "2 % 2 == 0");
+ mod2(3, 1, "3 % 2 == 1");
+ })
+})();
+
+(function() {
+ var reset = QUnit.reset;
+ function afterTest() {
+ ok( false, "reset should not modify test status" );
+ }
+ module("reset");
+ test("reset runs assertions", function() {
+ QUnit.reset = function() {
+ afterTest();
+ reset.apply( this, arguments );
+ };
+ });
+ test("reset runs assertions2", function() {
+ QUnit.reset = reset;
+ });
+})();
+
+module("noglobals", {
+ teardown: function() {
+ delete window.badGlobalVariableIntroducedInTest;
+ }
+});
+test("let teardown clean up globals", function() {
+ // this test will always pass if run without ?noglobals=true
+ window.badGlobalVariableIntroducedInTest = true;
+});